diff --git a/.github/workflows/ports.yml b/.github/workflows/ports.yml new file mode 100644 index 000000000..e9e6de284 --- /dev/null +++ b/.github/workflows/ports.yml @@ -0,0 +1,18 @@ +name: Build ports metadata + +on: + push: + pull_request: + paths: + - '.github/workflows/*.yml' + - 'tools/**' + - ports/** + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Build ports download metadata + run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards diff --git a/.github/workflows/ports_esp32.yml b/.github/workflows/ports_esp32.yml index b5107e748..319a27a10 100644 --- a/.github/workflows/ports_esp32.yml +++ b/.github/workflows/ports_esp32.yml @@ -24,13 +24,13 @@ jobs: - name: Build run: source tools/ci.sh && ci_esp32_build - build_idf43: + build_idf44: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Initialize lv_bindings submodule run: git submodule update --init --recursive lib/lv_bindings - name: Install packages - run: source tools/ci.sh && ci_esp32_idf43_setup + run: source tools/ci.sh && ci_esp32_idf44_setup - name: Build run: source tools/ci.sh && ci_esp32_build diff --git a/.gitignore b/.gitignore index f42407d5b..8a920570b 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ __pycache__/ GNUmakefile user.props ports/javascript/node_modules +.vscode/ # Generated rst files ###################### diff --git a/.gitmodules b/.gitmodules index 35aef82d3..7c02e8990 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,12 +26,13 @@ [submodule "lib/asf4"] path = lib/asf4 url = https://github.com/adafruit/asf4 + branch = circuitpython [submodule "lib/tinyusb"] path = lib/tinyusb url = https://github.com/hathach/tinyusb [submodule "lib/mynewt-nimble"] path = lib/mynewt-nimble - url = https://github.com/apache/mynewt-nimble.git + url = https://github.com/micropython/mynewt-nimble.git [submodule "lib/btstack"] path = lib/btstack url = https://github.com/bluekitchen/btstack.git diff --git a/.gitpod b/.gitpod index 2a94dbb35..7f7456b64 100644 --- a/.gitpod +++ b/.gitpod @@ -11,6 +11,8 @@ tasks: make -C ports/unix VARIANT=dev DEBUG=1 submodules make -j $(nproc) -C mpy-cross VARIANT=dev DEBUG=1 make -j $(nproc) -C ports/unix VARIANT=dev DEBUG=1 + source tools/ci.sh && ci_esp32_idf44_setup + source tools/ci.sh && ci_esp32_build command: | xrandr --fb 500x500 # Fix resolution for LVGL screens which are smaller ports/unix/micropython-dev -i lib/lv_bindings/examples/advanced_demo.py diff --git a/LICENSE b/LICENSE index 5b5c37f7d..2b9a64b89 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2021 Damien P. George +Copyright (c) 2013-2022 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/docs/conf.py b/docs/conf.py index 1a3c18a4f..741f8b343 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -66,7 +66,7 @@ master_doc = 'index' # General information about the project. project = 'MicroPython' -copyright = '- The MicroPython Documentation is Copyright © 2014-2021, Damien P. George, Paul Sokolovsky, and contributors' +copyright = '- The MicroPython Documentation is Copyright © 2014-2022, Damien P. George, Paul Sokolovsky, and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -74,7 +74,7 @@ copyright = '- The MicroPython Documentation is Copyright © 2014-2021, Damien P # # 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.17' +version = release = '1.18' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/develop/extendingmicropython.rst b/docs/develop/extendingmicropython.rst index 7fb1ae47a..b4029c421 100644 --- a/docs/develop/extendingmicropython.rst +++ b/docs/develop/extendingmicropython.rst @@ -16,4 +16,3 @@ live in the main MicroPython repository. cmodules.rst natmod.rst - \ No newline at end of file diff --git a/docs/develop/gettingstarted.rst b/docs/develop/gettingstarted.rst index 30b26071e..36062ddc0 100644 --- a/docs/develop/gettingstarted.rst +++ b/docs/develop/gettingstarted.rst @@ -4,7 +4,7 @@ Getting Started =============== This guide covers a step-by-step process on setting up version control, obtaining and building -a copy of the source code for a port, building the documentation, running tests, and a description of the +a copy of the source code for a port, building the documentation, running tests, and a description of the directory structure of the MicroPython code base. Source control with git @@ -16,7 +16,7 @@ code is pulled and pushed to and from the main repository. Install the respectiv of Git for your operating system to follow through the rest of the steps. .. note:: - For a reference on the installation instructions, please refer to + For a reference on the installation instructions, please refer to the `Git installation instructions `_. Learn about the basic git commands in this `Git Handbook `_ or any other sources on the internet. @@ -58,12 +58,12 @@ MicroPython repository. After the above configuration, your setup should be similar to this: .. code-block:: bash - + $ git remote -v - origin https://github.com//micropython (fetch) - origin https://github.com//micropython (push) - upstream https://github.com/micropython/micropython (fetch) - upstream https://github.com/micropython/micropython (push) + origin https://github.com//micropython (fetch) + origin https://github.com//micropython (push) + upstream https://github.com/micropython/micropython (fetch) + upstream https://github.com/micropython/micropython (push) You should now have a copy of the source code. By default, you are pointing to the master branch. To prepare for further development, it is recommended @@ -73,7 +73,7 @@ to work on a development branch. $ git checkout -b dev-branch -You can give it any name. You will have to compile MicroPython whenever you change +You can give it any name. You will have to compile MicroPython whenever you change to a different branch. Compile and build the code @@ -140,8 +140,8 @@ If it built successfully, you should see a message similar to this: .. code-block:: bash LINK mpy-cross - text data bss dec hex filename - 279328 776 880 280984 44998 mpy-cross + text data bss dec hex filename + 279328 776 880 280984 44998 mpy-cross .. note:: @@ -181,8 +181,8 @@ If MicroPython built correctly, you should see the following: .. code-block:: bash LINK micropython - text data bss dec hex filename - 412033 5680 2496 420209 66971 micropython + text data bss dec hex filename + 412033 5680 2496 420209 66971 micropython Now run it: @@ -215,7 +215,7 @@ as detailed in the :ref:`required_dependencies` section, then build: $ make submodules $ make -Please refer to the `stm32 documentation `_ +Please refer to the `stm32 documentation `_ for more details on flashing the firmware. .. note:: @@ -259,7 +259,7 @@ Build the docs: $ make html -Open ``docs/build/html/index.html`` in your browser to view the docs locally. Refer to the +Open ``docs/build/html/index.html`` in your browser to view the docs locally. Refer to the documentation on `importing your documentation `_ to use Read the Docs. diff --git a/docs/develop/index.rst b/docs/develop/index.rst index 7a6a6be67..327038f19 100644 --- a/docs/develop/index.rst +++ b/docs/develop/index.rst @@ -5,7 +5,7 @@ This chapter covers a tour of MicroPython from the perspective of a developer, c to MicroPython. It acts as a comprehensive resource on the implementation details of MicroPython for both novice and expert contributors. -Development around MicroPython usually involves modifying the core runtime, porting or +Development around MicroPython usually involves modifying the core runtime, porting or maintaining a new library. This guide describes at great depth, the implementation details of MicroPython including a getting started guide, compiler internals, porting MicroPython to a new platform and implementing a core MicroPython library. @@ -24,4 +24,3 @@ MicroPython to a new platform and implementing a core MicroPython library. publiccapi.rst extendingmicropython.rst porting.rst - \ No newline at end of file diff --git a/docs/develop/porting.rst b/docs/develop/porting.rst index 549227d76..ae0cfd8b0 100644 --- a/docs/develop/porting.rst +++ b/docs/develop/porting.rst @@ -53,8 +53,6 @@ The basic MicroPython firmware is implemented in the main port file, e.g ``main. mp_stack_ctrl_init(); gc_init(heap, heap + sizeof(heap)); mp_init(); - mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0); - mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); // Start a normal REPL; will exit when ctrl-D is entered on a blank line. pyexec_friendly_repl(); diff --git a/docs/develop/qstr.rst b/docs/develop/qstr.rst index cd1fc4786..5d1ac5bb4 100644 --- a/docs/develop/qstr.rst +++ b/docs/develop/qstr.rst @@ -59,7 +59,7 @@ Processing happens in the following stages: 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``, diff --git a/docs/differences/index_template.txt b/docs/differences/index_template.txt index 41ddeb6d3..dbbd7fc09 100644 --- a/docs/differences/index_template.txt +++ b/docs/differences/index_template.txt @@ -3,8 +3,21 @@ MicroPython differences from CPython ==================================== -The operations listed in this section produce conflicting results in MicroPython when compared to standard Python. -MicroPython implements Python 3.4 and some select features of Python 3.5. +MicroPython implements Python 3.4 and some select features of Python 3.5 and +above. The sections below describe the current status of these features. + +.. toctree:: + + ../differences/python_35.rst + ../differences/python_36.rst + ../differences/python_37.rst + ../differences/python_38.rst + ../differences/python_39.rst + +For the features of Python that are implemented by MicroPython, there are +sometimes differences in their behaviour compared to standard Python. The +operations listed in the sections below produce conflicting results in +MicroPython when compared to standard Python. .. toctree:: :maxdepth: 2 diff --git a/docs/differences/python_35.rst b/docs/differences/python_35.rst new file mode 100644 index 000000000..84c38c9cc --- /dev/null +++ b/docs/differences/python_35.rst @@ -0,0 +1,181 @@ +.. _python_35: + +Python 3.5 +========== + +Below is a list of finalised/accepted PEPs for Python 3.5 grouped into their impact to MicroPython. + + +----------------------------------------------------------------------------------------------------------+---------------+ + | **Extensions to the syntax:** | **Status** | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 448 `_ | additional unpacking generalizations | | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 465 `_ | a new matrix multiplication operator | Completed | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 492 `_ | coroutines with async and await syntax | Completed | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | **Extensions and changes to runtime:** | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 461 `_ | % formatting for binary strings | Completed | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 475 `_ | retrying system calls that fail with EINTR | Completed | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 479 `_ | change StopIteration handling inside generators | Completed | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | **Standard library changes:** | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 471 `_ | os.scandir() | | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 485 `_ | math.isclose(), a function for testing | Completed | + | | approximate equality | | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | **Miscellaneous changes:** | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 441 `_ | improved Python zip application support | | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 486 `_ | make the Python Laucher aware of virtual | | + | | environments | | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 484 `_ | type hints (advisory only) | In Progress | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 488 `_ | elimination of PYO files | Not relevant | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + | `PEP 489 `_ | redesigning extension module loading | | + +--------------------------------------------------------+-------------------------------------------------+---------------+ + + +Other Language Changes: + + +-----------------------------------------------------------------------------------------------------------+---------------+ + | Added the *namereplace* error handlers. The *backslashreplace* error handlers now work with decoding and | | + | translating. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | Property docstrings are now writable. This is especially useful for collections.namedtuple() docstrings | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | Circular imports involving relative imports are now supported. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + + +New Modules: + +* `typing `_ + +* `zipzap `_ + + +Changes to built-in modules: + + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `collections `_ | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *OrderedDict* class is now implemented in C, which makes it 4 to 100 times faster. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | *OrderedDict.items()* , *OrderedDict.keys()* , *OrderedDict.values()* views now support reversed() | | + | iteration. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The deque class now defines *index()*, *insert()*, and *copy()*, and supports the + and * operators. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | Docstrings produced by namedtuple() can now be updated. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The UserString class now implements the *__getnewargs__()*, *__rmod__()*, *casefold()*, *format_map()*, | | + | *isprintable()*, and *maketrans()* methods to match the corresponding methods of str. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `heapq `_ | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | Element comparison in *merge()* can now be customized by passing a key function in a new optional key | | + | keyword argument, and a new optional *reverse* keyword argument can be used to reverse element comparison | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `io `_ | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | A new *BufferedIOBase.readinto1()* method, that uses at most one call to the underlying raw stream's | | + | *RawIOBase.read()* or *RawIOBase.readinto()* methods | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `json `_ | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | JSON decoder now raises JSONDecodeError instead of ValueError to provide better context information about | | + | the error. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `math `_ | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | Two new constants have been added to the math module: *inf* and *nan*. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | A new function *isclose()* provides a way to test for approximate equality. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | A new *gcd()* function has been added. The *fractions.gcd()* function is now deprecated. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `os `_ | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The new *scandir()* function returning an iterator of DirEntry objects has been added. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *urandom()* function now uses the *getrandom()* syscall on Linux 3.17 or newer, and *getentropy()* on | | + | OpenBSD 5.6 and newer, removing the need to use /dev/urandom and avoiding failures due to potential file | | + | descriptor exhaustion. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | New *get_blocking()* and *set_blocking()* functions allow getting and setting a file descriptor's blocking| | + | mode (O_NONBLOCK.) | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | There is a new *os.path.commonpath()* function returning the longest common sub-path of each passed | | + | pathname | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `re `_ | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | References and conditional references to groups with fixed length are now allowed in lookbehind assertions| | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The number of capturing groups in regular expressions is no longer limited to 100. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *sub()* and *subn()* functions now replace unmatched groups with empty strings instead of raising an | | + | exception. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *re.error* exceptions have new attributes, msg, pattern, pos, lineno, and colno, that provide better | | + | context information about the error | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `socket `_ | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | Functions with timeouts now use a monotonic clock, instead of a system clock. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | A new *socket.sendfile()* method allows sending a file over a socket by using the high-performance | | + | *os.sendfile()* function on UNIX, resulting in uploads being from 2 to 3 times faster than when using | | + | plain *socket.send()* | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *socket.sendall()* method no longer resets the socket timeout every time bytes are received or sent. | | + | The socket timeout is now the maximum total duration to send all data. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The backlog argument of the *socket.listen()* method is now optional. By default it is set to SOMAXCONN or| | + | to 128, whichever is less. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `ssl `_ | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | Memory BIO Support | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | Application-Layer Protocol Negotiation Support | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | There is a new *SSLSocket.version()* method to query the actual protocol version in use. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The SSLSocket class now implements a *SSLSocket.sendfile()* method. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *SSLSocket.send()* method now raises either the *ssl.SSLWantReadError* or *ssl.SSLWantWriteError* | | + | exception on a non-blocking socket if the operation would block. Previously, it would return 0. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *cert_time_to_seconds()* function now interprets the input time as UTC and not as local time, per RFC | | + | 5280. Additionally, the return value is always an int. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | New *SSLObject.shared_ciphers()* and *SSLSocket.shared_ciphers()* methods return the list of ciphers sent | | + | by the client during the handshake. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *SSLSocket.do_handshake()*, *SSLSocket.read()*, *SSLSocket.shutdown()*, and *SSLSocket.write()* | | + | methods of the SSLSocket class no longer reset the socket timeout every time bytes are received or sent. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *match_hostname()* function now supports matching of IP addresses. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `sys `_ | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | A new *set_coroutine_wrapper()* function allows setting a global hook that will be called whenever a | | + | coroutine object is created by an async def function. A corresponding *get_coroutine_wrapper()* can be | | + | used to obtain a currently set wrapper. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | A new *is_finalizing()* function can be used to check if the Python interpreter is shutting down. | | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | `time `_ | + +-----------------------------------------------------------------------------------------------------------+---------------+ + | The *monotonic()* function is now always available | | + +-----------------------------------------------------------------------------------------------------------+---------------+ diff --git a/docs/differences/python_36.rst b/docs/differences/python_36.rst new file mode 100644 index 000000000..4ea874224 --- /dev/null +++ b/docs/differences/python_36.rst @@ -0,0 +1,191 @@ +.. _python_36: + +Python 3.6 +========== + +Python 3.6 beta 1 was released on 12 Sep 2016, and a summary of the new features can be found here: + + +-----------------------------------------------------------------------------------------------------------+--------------+ + | **New Syntax Features:** | **Status** | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 498 `_ | Literal String Formatting | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 515 `_ | Underscores in Numeric Literals | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 525 `_ | Asynchronous Generators | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 526 `_ | Syntax for Variable Annotations (provisional) | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 530 `_ | Asynchronous Comprehensions | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | **New Built-in Features:** | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 468 `_ | Preserving the order of *kwargs* in a function | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 487 `_ | Simpler customization of class creation | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 520 `_ | Preserving Class Attribute Definition Order | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | **Standard Library Changes:** | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 495 `_ | Local Time Disambiguation | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 506 `_ | Adding A Secrets Module To The Standard Library | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 519 `_ | Adding a file system path protocol | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | **CPython internals:** | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 509 `_ | Add a private version to dict | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 523 `_ | Adding a frame evaluation API to CPython | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | **Linux/Window Changes** | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 524 `_ | Make os.urandom() blocking on Linux | | + | | (during system startup) | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 528 `_ | Change Windows console encoding to UTF-8 | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + | `PEP 529 `_ | Change Windows filesystem encoding to UTF-8 | | + +--------------------------------------------------------+--------------------------------------------------+--------------+ + +Other Language Changes: + + +-------------------------------------------------------------------------------------------------------------+---------------+ + | A *global* or *nonlocal* statement must now textually appear before the first use of the affected name in | | + | the same scope. Previously this was a SyntaxWarning. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | It is now possible to set a special method to None to indicate that the corresponding operation is not | | + | available. For example, if a class sets *__iter__()* to *None* , the class is not iterable. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Long sequences of repeated traceback lines are now abbreviated as *[Previous line repeated {count} more | | + | times]* | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Import now raises the new exception *ModuleNotFoundError* when it cannot find a module. Code that currently | | + | checks for ImportError (in try-except) will still work. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Class methods relying on zero-argument *super()* will now work correctly when called from metaclass methods | | + | during class creation. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + +Changes to built-in modules: + + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `array `_ | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | Exhausted iterators of *array.array* will now stay exhausted even if the iterated array is extended. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `binascii `_ | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The b2a_base64() function now accepts an optional newline keyword argument to control whether the newline | | + | character is appended to the return value | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `cmath `_ | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The new cmath.tau (τ) constant has been added | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | New constants: *cmath.inf* and *cmath.nan* to match *math.inf* and *math.nan* , and also *cmath.infj* and | | + | *cmath.nanj* to match the format used by complex repr | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `collections `_ | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The new Collection abstract base class has been added to represent sized iterable container classes | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The new *Reversible* abstract base class represents iterable classes that also provide the *__reversed__()* | | + | method. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The new *AsyncGenerator* abstract base class represents asynchronous generators. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The *namedtuple()* function now accepts an optional keyword argument module, which, when specified, is used | | + | for the *__module__* attribute of the returned named tuple class. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The verbose and rename arguments for *namedtuple()* are now keyword-only. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | Recursive *collections.deque* instances can now be pickled. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `hashlib `_ | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | BLAKE2 hash functions were added to the module. *blake2b()* and *blake2s()* are always available and support | | + | the full feature set of BLAKE2. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The SHA-3 hash functions *sha3_224()*, *sha3_256()*, *sha3_384()*, *sha3_512()*, and *SHAKE* hash functions | | + | *shake_128()* and *shake_256()* were added. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The password-based key derivation function *scrypt()* is now available with OpenSSL 1.1.0 and newer. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `json `_ | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | *json.load()* and *json.loads()* now support binary input. Encoded JSON should be represented using either | | + | UTF-8, UTF-16, or UTF-32. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `math `_ | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The new math.tau (τ) constant has been added | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `os `_ | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | A new *close()* method allows explicitly closing a *scandir()* iterator. The *scandir()* iterator now | | + | supports the context manager protocol. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | On Linux, *os.urandom()* now blocks until the system urandom entropy pool is initialized to increase the | | + | security. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The Linux *getrandom()* syscall (get random bytes) is now exposed as the new *os.getrandom()* function. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `re `_ | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | Added support of modifier spans in regular expressions. Examples: *'(?i:p)ython'* matches 'python' and | | + | 'Python', but not 'PYTHON'; *'(?i)g(?-i:v)r'* matches *'GvR'* and *'gvr'*, but not *'GVR'* . | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | Match object groups can be accessed by *__getitem__*, which is equivalent to *group()*. So *mo['name']* is | | + | now equivalent to *mo.group('name')*. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | Match objects now support index-like objects as group indices. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `socket `_ | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The *ioctl()* function now supports the *SIO_LOOPBACK_FAST_PATH* control code. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The *getsockopt()* constants *SO_DOMAIN* , *SO_PROTOCOL*, *SO_PEERSEC* , and *SO_PASSSEC* are now supported. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The *setsockopt()* now supports the *setsockopt(level, optname, None, optlen: int)* form. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The socket module now supports the address family *AF_ALG* to interface with Linux Kernel crypto API. | | + | *ALG_*, *SOL_ALG* and *sendmsg_afalg()* were added. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | New Linux constants *TCP_USER_TIMEOUT* and *TCP_CONGESTION* were added. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `ssl `_ | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | ssl supports OpenSSL 1.1.0. The minimum recommend version is 1.0.2. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | 3DES has been removed from the default cipher suites and ChaCha20 Poly1305 cipher suites have been added. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | *SSLContext* has better default configuration for options and ciphers. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | SSL session can be copied from one client-side connection to another with the new *SSLSession* class. TLS | | + | session resumption can speed up the initial handshake, reduce latency and improve performance. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The new *get_ciphers()* method can be used to get a list of enabled ciphers in order of cipher priority. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | All constants and flags have been converted to *IntEnum* and *IntFlags*. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | Server and client-side specific TLS protocols for *SSLContext* were added. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | Added *SSLContext.post_handshake_auth* to enable and *ssl.SSLSocket.verify_client_post_handshake()* to | | + | initiate TLS 1.3 post-handshake authentication. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `struct `_ | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | now supports IEEE 754 half-precision floats via the 'e' format specifier. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `sys `_ | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The new *getfilesystemencodeerrors()* function returns the name of the error mode used to convert between | | + | Unicode filenames and bytes filenames. | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | `zlib `_ | | + +--------------------------------------------------------------------------------------------------------------+----------------+ + | The *compress()* and *decompress()* functions now accept keyword arguments | | + +--------------------------------------------------------------------------------------------------------------+----------------+ diff --git a/docs/differences/python_37.rst b/docs/differences/python_37.rst new file mode 100644 index 000000000..c46678e93 --- /dev/null +++ b/docs/differences/python_37.rst @@ -0,0 +1,95 @@ +.. _python_37: + +Python 3.7 +========== + +New Features: + + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | **Features:** | **Status** | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 538 `_ | Coercing the legacy C locale to a UTF-8 based | | + | | locale | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 539 `_ | A New C-API for Thread-Local Storage in CPython | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 540 `_ | UTF-8 mode | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 552 `_ | Deterministic pyc | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 553 `_ | Built-in breakpoint() | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 557 `_ | Data Classes | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 560 `_ | Core support for typing module and generic types | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 562 `_ | Module __getattr__ and __dir__ | Partially done | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 563 `_ | Postponed Evaluation of Annotations | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 564 `_ | Time functions with nanosecond resolution | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 565 `_ | Show DeprecationWarning in __main__ | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + | `PEP 567 `_ | Context Variables | | + +--------------------------------------------------------+--------------------------------------------------+----------------+ + +Other Language Changes: + + +----------------------------------------------------------------------------------------------------------+----------------+ + | async and await are now reserved keywords | Completed | + +----------------------------------------------------------------------------------------------------------+----------------+ + | dict objects must preserve insertion-order | | + +----------------------------------------------------------------------------------------------------------+----------------+ + | More than 255 arguments can now be passed to a function; a function can now have more than 255 parameters| | + +----------------------------------------------------------------------------------------------------------+----------------+ + | bytes.fromhex() and bytearray.fromhex() now ignore all ASCII whitespace, not only spaces | | + +----------------------------------------------------------------------------------------------------------+----------------+ + | str, bytes, and bytearray gained support for the new isascii() method, which can be used to test if a | | + | string or bytes contain only the ASCII characters | | + +----------------------------------------------------------------------------------------------------------+----------------+ + | ImportError now displays module name and module __file__ path whenfrom ... import ... fails | | + +----------------------------------------------------------------------------------------------------------+----------------+ + | Circular imports involving absolute imports with binding a submodule to a name are now supported | | + +----------------------------------------------------------------------------------------------------------+----------------+ + | object.__format__(x, '') is now equivalent to str(x) rather than format(str(self), '') | | + +----------------------------------------------------------------------------------------------------------+----------------+ + | In order to better support dynamic creation of stack traces, types.TracebackType can now be instantiated | | + | from Python code, and the tb_next attribute on tracebacks is now writable | | + +----------------------------------------------------------------------------------------------------------+----------------+ + | When using the -m switch, sys.path[0] is now eagerly expanded to the full starting directory path, rather| | + | than being left as the empty directory (which allows imports from the current working directory at the | | + | time when an import occurs) | | + +----------------------------------------------------------------------------------------------------------+----------------+ + | The new -X importtime option or the PYTHONPROFILEIMPORTTIME environment variable can be used to show the | | + | timing of each module import | | + +----------------------------------------------------------------------------------------------------------+----------------+ + +Changes to built-in modules: + + +------------------------------------------------------------------------------------------------------------+----------------+ + | `asyncio `_ | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | asyncio (many, may need a separate ticket) | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | `gc `_ | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | New features include *gc.freeze()*, *gc.unfreeze()*, *gc-get_freeze_count* | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | `math `_ | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | math.remainder() added to implement IEEE 754-style remainder | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | `re `_ | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | A number of tidy up features including better support for splitting on empty strings and copy support for | | + | compiled expressions and match objects | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | `sys `_ | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | sys.breakpointhook() added. sys.get(/set)_coroutine_origin_tracking_depth() added | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | `time `_ | | + +------------------------------------------------------------------------------------------------------------+----------------+ + | Mostly updates to support nanosecond resolution in PEP564, see above | | + +------------------------------------------------------------------------------------------------------------+----------------+ diff --git a/docs/differences/python_38.rst b/docs/differences/python_38.rst new file mode 100644 index 000000000..47840a8b4 --- /dev/null +++ b/docs/differences/python_38.rst @@ -0,0 +1,118 @@ +.. _python_38: + +Python 3.8 +========== + +Python 3.8.0 (final) was released on the 14 October 2019. The Features for 3.8 +are defined in `PEP 569 `_ and +a detailed description of the changes can be found in What's New in `Python +3.8. `_ + + +--------------------------------------------------------+---------------------------------------------------+---------------+ + | **Features:** | Status | + +--------------------------------------------------------+---------------------------------------------------+---------------+ + | `PEP 570 `_ | Positional-only arguments | | + +--------------------------------------------------------+---------------------------------------------------+---------------+ + | `PEP 572 `_ | Assignment Expressions | | + +--------------------------------------------------------+---------------------------------------------------+---------------+ + | `PEP 574 `_ | Pickle protocol 5 with out-of-band data | | + +--------------------------------------------------------+---------------------------------------------------+---------------+ + | `PEP 578 `_ | Runtime audit hooks | | + +--------------------------------------------------------+---------------------------------------------------+---------------+ + | `PEP 587 `_ | Python Initialization Configuration | | + +--------------------------------------------------------+---------------------------------------------------+---------------+ + | `PEP 590 `_ | Vectorcall: a fast calling protocol for CPython | | + +--------------------------------------------------------+---------------------------------------------------+---------------+ + | **Miscellaneous** | + +------------------------------------------------------------------------------------------------------------+---------------+ + | f-strings support = for self-documenting expressions and debugging | Completed | + +------------------------------------------------------------------------------------------------------------+---------------+ + +Other Language Changes: + + +------------------------------------------------------------------------------------------------------------+-------------+ + | A *continue* statement was illegal in the *finally* clause due to a problem with the implementation. In | Completed | + | Python 3.8 this restriction was lifted | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | The *bool*, *int* , and *fractions.Fraction* types now have an *as_integer_ratio()* method like that found | | + | in *float* and *decimal.Decimal* | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Constructors of *int*, *float* and *complex* will now use the *__index__()* special method, if available | | + | and the corresponding method *__int__()*, *__float__()* or *__complex__()* is not available | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Added support of *\N{name}* escapes in regular expressions | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Dict and dictviews are now iterable in reversed insertion order using *reversed()* | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | The syntax allowed for keyword names in function calls was further restricted. In particular, | | + | f((keyword)=arg) is no longer allowed | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Generalized iterable unpacking in yield and return statements no longer requires enclosing parentheses | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | When a comma is missed in code such as [(10, 20) (30, 40)], the compiler displays a SyntaxWarning with a | | + | helpful suggestion | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Arithmetic operations between subclasses of *datetime.date* or *datetime.datetime* and *datetime.timedelta*| | + | objects now return an instance of the subclass, rather than the base class | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | When the Python interpreter is interrupted by *Ctrl-C (SIGINT)* and the resulting *KeyboardInterrupt* | | + | exception is not caught, the Python process now exits via a SIGINT signal or with the correct exit code | | + | such that the calling process can detect that it died due to a *Ctrl-C* | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Some advanced styles of programming require updating the *types.CodeType* object for an existing function | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | For integers, the three-argument form of the pow() function now permits the exponent to be negative in the | | + | case where the base is relatively prime to the modulus | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Dict comprehensions have been synced-up with dict literals so that the key is computed first and the value | | + | second | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | The *object.__reduce__()* method can now return a tuple from two to six elements long | | + +------------------------------------------------------------------------------------------------------------+-------------+ + +Changes to built-in modules: + + +------------------------------------------------------------------------------------------------------------+-------------+ + | `asyncio` | + +------------------------------------------------------------------------------------------------------------+-------------+ + | *asyncio.run()* has graduated from the provisional to stable API | Completed | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Running *python -m asyncio* launches a natively async REPL | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | The exception *asyncio.CancelledError* now inherits from *BaseException* rather than *Exception* and no | Completed | + | longer inherits from *concurrent.futures.CancelledError* | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Added *asyncio.Task.get_coro()* for getting the wrapped coroutine within an *asyncio.Task* | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Asyncio tasks can now be named, either by passing the name keyword argument to *asyncio.create_task()* or | | + | the *create_task()* event loop method, or by calling the *set_name()* method on the task object | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Added support for Happy Eyeballs to *asyncio.loop.create_connection()*. To specify the behavior, two new | | + | parameters have been added: *happy_eyeballs_delay* and interleave. | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | `gc` | + +------------------------------------------------------------------------------------------------------------+-------------+ + | *get_objects()* can now receive an optional generation parameter indicating a generation to get objects | | + | from. (Note, though, that while *gc* is a built-in, *get_objects()* is not implemented for MicroPython) | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | `math` | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Added new function *math.dist()* for computing Euclidean distance between two points | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Expanded the *math.hypot()* function to handle multiple dimensions | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Added new function, *math.prod()*, as analogous function to *sum()* that returns the product of a "start" | | + | value (default: 1) times an iterable of numbers | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Added two new combinatoric functions *math.perm()* and *math.comb()* | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Added a new function *math.isqrt()* for computing accurate integer square roots without conversion to | | + | floating point | | + +------------------------------------------------------------------------------------------------------------+-------------+ + | The function *math.factorial()* no longer accepts arguments that are not int-like | Completed | + +------------------------------------------------------------------------------------------------------------+-------------+ + | `sys` | + +------------------------------------------------------------------------------------------------------------+-------------+ + | Add new *sys.unraisablehook()* function which can be overridden to control how "unraisable exceptions" | | + | are handled | | + +------------------------------------------------------------------------------------------------------------+-------------+ diff --git a/docs/differences/python_39.rst b/docs/differences/python_39.rst new file mode 100644 index 000000000..6852dd635 --- /dev/null +++ b/docs/differences/python_39.rst @@ -0,0 +1,121 @@ +.. _python_39: + +Python 3.9 +========== + +Python 3.9.0 (final) was released on the 5th October 2020. The Features for 3.9 are +defined in `PEP 596 `_ +and a detailed description of the changes can be found in +`What's New in Python 3.9 `_ + + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | **Features:** | | **Status** | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 573 `_ | fast access to module state from methods of C | | + | | extension types | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 584 `_ | union operators added to dict | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 585 `_ | type hinting generics in standard collections | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 593 `_ | flexible function and variable annotations | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 602 `_ | CPython adopts an annual release cycle. Instead of | | + | | annual, aiming for two month release cycle | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 614 `_ | relaxed grammar restrictions on decorators | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 615 `_ | the IANA Time Zone Database is now present in the | | + | | standard library in the zoneinfo module | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 616 `_ | string methods to remove prefixes and suffixes | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 617 `_ | CPython now uses a new parser based on PEG | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + +Other Language Changes: + + +-------------------------------------------------------------------------------------------------------------+---------------+ + | *__import__()* now raises *ImportError* instead of *ValueError* | Completed | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Python now gets the absolute path of the script filename specified on the command line (ex: *python3* | | + | *script.py*): the *__file__* attribute of the *__main__* module became an absolute path, rather than a | | + | relative path | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | By default, for best performance, the errors argument is only checked at the first encoding/decoding error | | + | and the encoding argument is sometimes ignored for empty strings | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | *"".replace("", s, n)* now returns *s* instead of an empty string for all non-zero n. It is now consistent | | + | with *"".replace("", s)* | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Any valid expression can now be used as a decorator. Previously, the grammar was much more restrictive | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Parallel running of *aclose()* / *asend()* / *athrow()* is now prohibited, and *ag_running* now reflects | | + | the actual running status of the async generator | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Unexpected errors in calling the *__iter__* method are no longer masked by TypeError in the in operator and | | + | functions contains(), indexOf() and countOf() of the operator module | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Unparenthesized lambda expressions can no longer be the expression part in an if clause in comprehensions | | + | and generator expressions | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + +Changes to built-in modules: + + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `asyncio` | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Due to significant security concerns, the reuse_address parameter of *asyncio.loop.create_datagram_endpoint()*| | + | is no longer supported | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Added a new coroutine *shutdown_default_executor()* that schedules a shutdown for the default executor that | | + | waits on the *ThreadPoolExecutor* to finish closing. Also, *asyncio.run()* has been updated to use the new | | + | coroutine. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Added *asyncio.PidfdChildWatcher*, a Linux-specific child watcher implementation that polls process file | | + | descriptors | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | added a new *coroutine asyncio.to_thread()* | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | When cancelling the task due to a timeout, *asyncio.wait_for()* will now wait until the cancellation is | | + | complete also in the case when timeout is <= 0, like it does with positive timeouts | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | *asyncio* now raises *TyperError* when calling incompatible methods with an *ssl.SSLSocket* socket | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `gc` | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Garbage collection does not block on resurrected objects | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Added a new function *gc.is_finalized()* to check if an object has been finalized by the garbage collector | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `math` | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Expanded the *math.gcd()* function to handle multiple arguments. Formerly, it only supported two arguments | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Added *math.lcm()*: return the least common multiple of specified arguments | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Added *math.nextafter()*: return the next floating-point value after x towards y | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Added *math.ulp()*: return the value of the least significant bit of a float | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `os` | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Exposed the Linux-specific *os.pidfd_open()* and *os.P_PIDFD* | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The *os.unsetenv()* function is now also available on Windows | Completed | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The *os.putenv()* and *os.unsetenv()* functions are now always available | Completed | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Added *os.waitstatus_to_exitcode()* function: convert a wait status to an exit code | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `random` | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Added a new *random.Random.randbytes* method: generate random bytes | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `sys` | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Added a new *sys.platlibdir* attribute: name of the platform-specific library directory | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Previously, *sys.stderr* was block-buffered when non-interactive. Now stderr defaults to always being | | + | line-buffered | | + +---------------------------------------------------------------------------------------------------------------+---------------+ diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 3153ebd57..337f87b66 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -16,7 +16,7 @@ working with this board it may be useful to get an overview of the microcontroll :maxdepth: 1 general.rst - tutorial/intro.rst + tutorial/index.rst Installing MicroPython ---------------------- @@ -218,20 +218,48 @@ range from 1Hz to 40MHz but there is a tradeoff; as the base frequency *increases* the duty resolution *decreases*. See `LED Control `_ for more details. -Currently the duty cycle has to be in the range of 0-1023. -Use the ``machine.PWM`` class:: +Use the :ref:`machine.PWM ` class:: from machine import Pin, PWM - pwm0 = PWM(Pin(0)) # create PWM object from a pin - pwm0.freq() # get current frequency - pwm0.freq(1000) # set frequency - pwm0.duty() # get current duty cycle - pwm0.duty(200) # set duty cycle - pwm0.deinit() # turn off PWM on the pin + pwm0 = PWM(Pin(0)) # create PWM object from a pin + freq = pwm0.freq() # get current frequency (default 5kHz) + pwm0.freq(1000) # set PWM frequency from 1Hz to 40MHz - pwm2 = PWM(Pin(2), freq=20000, duty=512) # create and configure in one go + duty = pwm0.duty() # get current duty cycle, range 0-1023 (default 512, 50%) + pwm0.duty(256) # set duty cycle from 0 to 1023 as a ratio duty/1023, (now 25%) + + duty_u16 = pwm0.duty_u16() # get current duty cycle, range 0-65535 + pwm0.duty_u16(2**16*3//4) # set duty cycle from 0 to 65535 as a ratio duty_u16/65535, (now 75%) + + duty_ns = pwm0.duty_ns() # get current pulse width in ns + pwm0.duty_ns(250_000) # set pulse width in nanoseconds from 0 to 1_000_000_000/freq, (now 25%) + + pwm0.deinit() # turn off PWM on the pin + + pwm2 = PWM(Pin(2), freq=20000, duty=512) # create and configure in one go + print(pwm2) # view PWM settings + +ESP chips have different hardware peripherals: + +===================================================== ======== ======== ======== +Hardware specification ESP32 ESP32-S2 ESP32-C3 +----------------------------------------------------- -------- -------- -------- +Number of groups (speed modes) 2 1 1 +Number of timers per group 4 4 4 +Number of channels per group 8 8 6 +----------------------------------------------------- -------- -------- -------- +Different PWM frequencies (groups * timers) 8 4 4 +Total PWM channels (Pins, duties) (groups * channels) 16 8 6 +===================================================== ======== ======== ======== + +A maximum number of PWM channels (Pins) are available on the ESP32 - 16 channels, +but only 8 different PWM frequencies are available, the remaining 8 channels must +have the same frequency. On the other hand, 16 independent PWM duty cycles are +possible at the same frequency. + +See more examples in the :ref:`esp32_pwm` tutorial. ADC (analog to digital conversion) ---------------------------------- @@ -391,14 +419,14 @@ I2S bus See :ref:`machine.I2S `. :: from machine import I2S, Pin - + i2s = I2S(0, sck=Pin(13), ws=Pin(14), sd=Pin(34), mode=I2S.TX, bits=16, format=I2S.STEREO, rate=44100, ibuf=40000) # create I2S object i2s.write(buf) # write buffer of audio samples to I2S device - + i2s = I2S(1, sck=Pin(33), ws=Pin(25), sd=Pin(32), mode=I2S.RX, bits=16, format=I2S.MONO, rate=22050, ibuf=40000) # create I2S object i2s.readinto(buf) # fill buffer with audio samples from I2S device - -The I2S class is currently available as a Technical Preview. During the preview period, feedback from + +The I2S class is currently available as a Technical Preview. During the preview period, feedback from users is encouraged. Based on this feedback, the I2S class API and implementation may be changed. ESP32 has two I2S buses with id=0 and id=1 @@ -481,7 +509,7 @@ The RMT is ESP32-specific and allows generation of accurate digital pulses with 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 + r.write_pulses((1, 20, 2, 40), 0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns OneWire driver -------------- @@ -545,6 +573,9 @@ For low-level driving of a NeoPixel:: 400kHz) devices by passing ``timing=0`` when constructing the ``NeoPixel`` object. +The low-level driver uses an RMT channel by default. To configure this see +`RMT.bitstream_channel`. + APA102 (DotStar) uses a different driver as it has an additional clock pin. Capacitive touch diff --git a/docs/esp32/tutorial/index.rst b/docs/esp32/tutorial/index.rst new file mode 100644 index 000000000..c6242d731 --- /dev/null +++ b/docs/esp32/tutorial/index.rst @@ -0,0 +1,23 @@ +.. _esp32_tutorial: + +MicroPython tutorial for ESP32 +============================== + +This tutorial is intended to get you started using MicroPython on the ESP32 +system-on-a-chip. If it is your first time it is recommended to follow the +tutorial through in the order below. Otherwise the sections are mostly self +contained, so feel free to skip to those that interest you. + +The tutorial does not assume that you know Python, but it also does not attempt +to explain any of the details of the Python language. Instead it provides you +with commands that are ready to run, and hopes that you will gain a bit of +Python knowledge along the way. To learn more about Python itself please refer +to ``__. + +.. toctree:: + :maxdepth: 1 + :numbered: + + intro.rst + pwm.rst + peripheral_access.rst diff --git a/docs/esp32/tutorial/intro.rst b/docs/esp32/tutorial/intro.rst index 4c5673834..8ed42dbd3 100644 --- a/docs/esp32/tutorial/intro.rst +++ b/docs/esp32/tutorial/intro.rst @@ -34,8 +34,8 @@ Please refer to the documentation for your board for further details. Getting the firmware -------------------- -The first thing you need to do is download the most recent MicroPython firmware -.bin file to load onto your ESP32 device. You can download it from the +The first thing you need to do is download the most recent MicroPython firmware +.bin file to load onto your ESP32 device. You can download it from the `MicroPython downloads page `_. From here, you have 3 main choices: diff --git a/docs/esp32/tutorial/peripheral_access.rst b/docs/esp32/tutorial/peripheral_access.rst new file mode 100644 index 000000000..3304c341d --- /dev/null +++ b/docs/esp32/tutorial/peripheral_access.rst @@ -0,0 +1,44 @@ +Accessing peripherals directly via registers +============================================ + +The ESP32's peripherals can be controlled via direct register reads and writes. +This requires reading the datasheet to know what registers to use and what +values to write to them. The following example shows how to turn on and change +the prescaler of the MCPWM0 peripheral. + +.. code-block:: python3 + + from micropython import const + from machine import mem32 + + # Define the register addresses that will be used. + DR_REG_DPORT_BASE = const(0x3FF00000) + DPORT_PERIP_CLK_EN_REG = const(DR_REG_DPORT_BASE + 0x0C0) + DPORT_PERIP_RST_EN_REG = const(DR_REG_DPORT_BASE + 0x0C4) + DPORT_PWM0_CLK_EN = const(1 << 17) + MCPWM0 = const(0x3FF5E000) + MCPWM1 = const(0x3FF6C000) + + # Enable CLK and disable RST. + print(hex(mem32[DPORT_PERIP_CLK_EN_REG] & 0xffffffff)) + print(hex(mem32[DPORT_PERIP_RST_EN_REG] & 0xffffffff)) + mem32[DPORT_PERIP_CLK_EN_REG] |= DPORT_PWM0_CLK_EN + mem32[DPORT_PERIP_RST_EN_REG] &= ~DPORT_PWM0_CLK_EN + print(hex(mem32[DPORT_PERIP_CLK_EN_REG] & 0xffffffff)) + print(hex(mem32[DPORT_PERIP_RST_EN_REG] & 0xffffffff)) + + # Change the MCPWM0 prescaler. + print(hex(mem32[MCPWM0])) # read PWM_CLK_CFG_REG (reset value = 0) + mem32[MCPWM0] = 0x55 # change PWM_CLK_PRESCALE + print(hex(mem32[MCPWM0])) # read PWM_CLK_CFG_REG + +Note that before a peripheral can be used its clock must be enabled and it must +be taken out of reset. In the above example the following registers are used +for this: + +- ``DPORT_PERI_CLK_EN_REG``: used to enable a peripheral clock + +- ``DPORT_PERI_RST_EN_REG``: used to reset (or take out of reset) a peripheral + +The MCPWM0 peripheral is in bit position 17 of the above two registers, hence +the value of ``DPORT_PWM0_CLK_EN``. diff --git a/docs/esp32/tutorial/pwm.rst b/docs/esp32/tutorial/pwm.rst new file mode 100644 index 000000000..12d10a86b --- /dev/null +++ b/docs/esp32/tutorial/pwm.rst @@ -0,0 +1,115 @@ +.. _esp32_pwm: + +Pulse Width Modulation +====================== + +Pulse width modulation (PWM) is a way to get an artificial analog output on a +digital pin. It achieves this by rapidly toggling the pin from low to high. +There are two parameters associated with this: the frequency of the toggling, +and the duty cycle. The duty cycle is defined to be how long the pin is high +compared with the length of a single period (low plus high time). Maximum +duty cycle is when the pin is high all of the time, and minimum is when it is +low all of the time. + +* More comprehensive example with all 16 PWM channels and 8 timers:: + + from machine import Pin, PWM + try: + f = 100 # Hz + d = 1024 // 16 # 6.25% + pins = (15, 2, 4, 16, 18, 19, 22, 23, 25, 26, 27, 14 , 12, 13, 32, 33) + pwms = [] + for i, pin in enumerate(pins): + pwms.append(PWM(Pin(pin), freq=f * (i // 2 + 1), duty= 1023 if i==15 else d * (i + 1))) + print(pwms[i]) + finally: + for pwm in pwms: + try: + pwm.deinit() + except: + pass + + Output is:: + + PWM(Pin(15), freq=100, duty=64, resolution=10, mode=0, channel=0, timer=0) + PWM(Pin(2), freq=100, duty=128, resolution=10, mode=0, channel=1, timer=0) + PWM(Pin(4), freq=200, duty=192, resolution=10, mode=0, channel=2, timer=1) + PWM(Pin(16), freq=200, duty=256, resolution=10, mode=0, channel=3, timer=1) + PWM(Pin(18), freq=300, duty=320, resolution=10, mode=0, channel=4, timer=2) + PWM(Pin(19), freq=300, duty=384, resolution=10, mode=0, channel=5, timer=2) + PWM(Pin(22), freq=400, duty=448, resolution=10, mode=0, channel=6, timer=3) + PWM(Pin(23), freq=400, duty=512, resolution=10, mode=0, channel=7, timer=3) + PWM(Pin(25), freq=500, duty=576, resolution=10, mode=1, channel=0, timer=0) + PWM(Pin(26), freq=500, duty=640, resolution=10, mode=1, channel=1, timer=0) + PWM(Pin(27), freq=600, duty=704, resolution=10, mode=1, channel=2, timer=1) + PWM(Pin(14), freq=600, duty=768, resolution=10, mode=1, channel=3, timer=1) + PWM(Pin(12), freq=700, duty=832, resolution=10, mode=1, channel=4, timer=2) + PWM(Pin(13), freq=700, duty=896, resolution=10, mode=1, channel=5, timer=2) + PWM(Pin(32), freq=800, duty=960, resolution=10, mode=1, channel=6, timer=3) + PWM(Pin(33), freq=800, duty=1023, resolution=10, mode=1, channel=7, timer=3) + +* Example of a smooth frequency change:: + + from utime import sleep + from machine import Pin, PWM + + F_MIN = 500 + F_MAX = 1000 + + f = F_MIN + delta_f = 1 + + p = PWM(Pin(5), f) + print(p) + + while True: + p.freq(f) + + sleep(10 / F_MIN) + + f += delta_f + if f >= F_MAX or f <= F_MIN: + delta_f = -delta_f + + See PWM wave at Pin(5) with an oscilloscope. + +* Example of a smooth duty change:: + + from utime import sleep + from machine import Pin, PWM + + DUTY_MAX = 2**16 - 1 + + duty_u16 = 0 + delta_d = 16 + + p = PWM(Pin(5), 1000, duty_u16=duty_u16) + print(p) + + while True: + p.duty_u16(duty_u16) + + sleep(1 / 1000) + + duty_u16 += delta_d + if duty_u16 >= DUTY_MAX: + duty_u16 = DUTY_MAX + delta_d = -delta_d + elif duty_u16 <= 0: + duty_u16 = 0 + delta_d = -delta_d + + See PWM wave at Pin(5) with an oscilloscope. + +Note: the Pin.OUT mode does not need to be specified. The channel is initialized +to PWM mode internally once for each Pin that is passed to the PWM constructor. + +The following code is wrong:: + + pwm = PWM(Pin(5, Pin.OUT), freq=1000, duty=512) # Pin(5) in PWM mode here + pwm = PWM(Pin(5, Pin.OUT), freq=500, duty=256) # Pin(5) in OUT mode here, PWM is off + +Use this code instead:: + + pwm = PWM(Pin(5), freq=1000, duty=512) + pwm.init(freq=500, duty=256) diff --git a/docs/esp8266/tutorial/intro.rst b/docs/esp8266/tutorial/intro.rst index a5deb3532..ac46e68b5 100644 --- a/docs/esp8266/tutorial/intro.rst +++ b/docs/esp8266/tutorial/intro.rst @@ -41,8 +41,8 @@ Please refer to the documentation for your board for further details. Getting the firmware -------------------- -The first thing you need to do is download the most recent MicroPython firmware -.bin file to load onto your ESP8266 device. You can download it from the +The first thing you need to do is download the most recent MicroPython firmware +.bin file to load onto your ESP8266 device. You can download it from the `MicroPython downloads page `_. From here, you have 3 main choices @@ -64,7 +64,7 @@ such, only daily builds for 512kb modules are provided. Deploying the firmware ---------------------- -Once you have the MicroPython firmware (compiled code), you need to load it onto +Once you have the MicroPython firmware (compiled code), you need to load it onto your ESP8266 device. There are two main steps to do this: first you need to put your device in boot-loader mode, and second you need to copy across the firmware. The exact procedure for these steps is highly dependent on the diff --git a/docs/esp8266/tutorial/ssd1306.rst b/docs/esp8266/tutorial/ssd1306.rst index 4dca82afc..8651522e0 100644 --- a/docs/esp8266/tutorial/ssd1306.rst +++ b/docs/esp8266/tutorial/ssd1306.rst @@ -66,8 +66,8 @@ Subclassing FrameBuffer provides support for graphics primitives:: display.hline(0, 8, 4, 1) # draw horizontal line x=0, y=8, width=4, colour=1 display.vline(0, 8, 4, 1) # draw vertical line x=0, y=8, height=4, colour=1 display.line(0, 0, 127, 63, 1) # draw a line from 0,0 to 127,63 - display.rect(10, 10, 107, 43, 1) # draw a rectangle outline 10,10 to 107,43, colour=1 - display.fill_rect(10, 10, 107, 43, 1) # draw a solid rectangle 10,10 to 107,43, colour=1 + display.rect(10, 10, 107, 43, 1) # draw a rectangle outline 10,10 to 117,53, colour=1 + display.fill_rect(10, 10, 107, 43, 1) # draw a solid rectangle 10,10 to 117,53, colour=1 display.text('Hello World', 0, 0, 1) # draw some text at x=0, y=0, colour=1 display.scroll(20, 0) # scroll 20 pixels to the right diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst index 7ab4d6e88..7663199e9 100644 --- a/docs/library/bluetooth.rst +++ b/docs/library/bluetooth.rst @@ -49,7 +49,7 @@ Configuration - ``'mac'``: The current address in use, depending on the current address mode. This returns a tuple of ``(addr_type, addr)``. - See :meth:`gatts_write ` for details about address type. + See :meth:`gatts_write ` for details about address type. This may only be queried while the interface is currently active. @@ -359,13 +359,27 @@ Central Role A central device can connect to peripherals that it has discovered using the observer role (see :meth:`gap_scan`) or with a known address. -.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, /) +.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, min_conn_interval_us=None, max_conn_interval_us=None, /) Connect to a peripheral. See :meth:`gap_scan ` for details about address types. - On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised. + To cancel an outstanding connection attempt early, call + ``gap_connect(None)``. + + On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised. If + cancelling a connection attempt, the ``_IRQ_PERIPHERAL_DISCONNECT`` event + will be raised. + + The device will wait up to *scan_duration_ms* to receive an advertising + payload from the device. + + The connection interval can be configured in **micro**\ seconds using either + or both of *min_conn_interval_us* and *max_conn_interval_us*. Otherwise a + default interval will be chosen, typically between 30000 and 50000 + microseconds. A shorter interval will increase throughput, at the expense + of power usage. Peripheral Role diff --git a/docs/library/esp.rst b/docs/library/esp.rst index b9ae57bd9..5fb370065 100644 --- a/docs/library/esp.rst +++ b/docs/library/esp.rst @@ -4,7 +4,7 @@ .. module:: esp :synopsis: functions related to the ESP8266 and ESP32 -The ``esp`` module contains specific functions related to both the ESP8266 and +The ``esp`` module contains specific functions related to both the ESP8266 and ESP32 modules. Some functions are only available on one or the other of these ports. diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index e3c25d265..ff1c99a55 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -250,6 +250,17 @@ For more details see Espressif's `ESP-IDF RMT documentation. new sequence of pulses. Looping sequences longer than 126 pulses is not supported by the hardware. +.. staticmethod:: RMT.bitstream_channel([value]) + + Select which RMT channel is used by the `machine.bitstream` implementation. + *value* can be ``None`` or a valid RMT channel number. The default RMT + channel is the highest numbered one. + + Passing in ``None`` disables the use of RMT and instead selects a bit-banging + implementation for `machine.bitstream`. + + Passing in no argument will not change the channel. This function returns + the current channel number. Ultra-Low-Power co-processor ---------------------------- diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 13502cc7a..098ada815 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -19,11 +19,11 @@ For example:: import framebuf # FrameBuffer needs 2 bytes for every RGB565 pixel - fbuf = framebuf.FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565) + fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565) fbuf.fill(0) fbuf.text('MicroPython!', 0, 0, 0xffff) - fbuf.hline(0, 10, 96, 0xffff) + fbuf.hline(0, 9, 96, 0xffff) Constructors ------------ diff --git a/docs/library/heapq.rst b/docs/library/heapq.rst index 5e808d544..673871c5f 100644 --- a/docs/library/heapq.rst +++ b/docs/library/heapq.rst @@ -23,7 +23,7 @@ Functions Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if ``heap`` is empty. - + The returned item will be the smallest item in the ``heap``. .. function:: heapify(x) diff --git a/docs/library/index.rst b/docs/library/index.rst index 070e9f966..2b1d6b965 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -65,6 +65,7 @@ library. json.rst math.rst os.rst + random.rst re.rst select.rst socket.rst @@ -119,6 +120,7 @@ The following libraries are specific to the pyboard. :maxdepth: 2 pyb.rst + stm.rst lcd160cr.rst diff --git a/docs/library/lcd160cr.rst b/docs/library/lcd160cr.rst index 85e4b8f07..25903eb22 100644 --- a/docs/library/lcd160cr.rst +++ b/docs/library/lcd160cr.rst @@ -313,7 +313,7 @@ Advanced commands specified by :meth:`LCD160CR.set_spi_win`, starting from the top-left corner. The `framebuf `_ module can be used to construct frame buffers - and provides drawing primitives. Using a frame buffer will improve + and provides drawing primitives. Using a frame buffer will improve performance of animations when compared to drawing directly to the screen. .. method:: LCD160CR.set_scroll(on) diff --git a/docs/library/machine.ADCWiPy.rst b/docs/library/machine.ADCWiPy.rst index e500d0089..d4ccde205 100644 --- a/docs/library/machine.ADCWiPy.rst +++ b/docs/library/machine.ADCWiPy.rst @@ -27,13 +27,13 @@ Constructors Create an ADC object associated with the given pin. This allows you to then read analog values on that pin. For more info check the `pinout and alternate functions - table. `_ + table. `_ - .. warning:: + .. warning:: - ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it - can withstand). When GP2, GP3, GP4 or GP5 are remapped to the - ADC block, 1.8 V is the maximum. If these pins are used in digital mode, + ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it + can withstand). When GP2, GP3, GP4 or GP5 are remapped to the + ADC block, 1.8 V is the maximum. If these pins are used in digital mode, then the maximum allowed input is 3.6V. Methods diff --git a/docs/library/machine.I2S.rst b/docs/library/machine.I2S.rst index 45877a5ae..abfbb0878 100644 --- a/docs/library/machine.I2S.rst +++ b/docs/library/machine.I2S.rst @@ -4,91 +4,91 @@ class I2S -- Inter-IC Sound bus protocol ======================================== -I2S is a synchronous serial protocol used to connect digital audio devices. +I2S is a synchronous serial protocol used to connect digital audio devices. At the physical level, a bus consists of 3 lines: SCK, WS, SD. The I2S class supports controller operation. Peripheral operation is not supported. -The I2S class is currently available as a Technical Preview. During the preview period, feedback from +The I2S class is currently available as a Technical Preview. During the preview period, feedback from users is encouraged. Based on this feedback, the I2S class API and implementation may be changed. I2S objects can be created and initialized using:: from machine import I2S from machine import Pin - + # ESP32 sck_pin = Pin(14) # Serial clock output ws_pin = Pin(13) # Word clock output sd_pin = Pin(12) # Serial data output - + or - + # PyBoards sck_pin = Pin("Y6") # Serial clock output ws_pin = Pin("Y5") # Word clock output sd_pin = Pin("Y8") # Serial data output - - audio_out = I2S(2, + + audio_out = I2S(2, sck=sck_pin, ws=ws_pin, sd=sd_pin, - mode=I2S.TX, - bits=16, + mode=I2S.TX, + bits=16, format=I2S.MONO, - rate=44100, + rate=44100, ibuf=20000) - - audio_in = I2S(2, + + audio_in = I2S(2, sck=sck_pin, ws=ws_pin, sd=sd_pin, - mode=I2S.RX, - bits=32, + mode=I2S.RX, + bits=32, format=I2S.STEREO, - rate=22050, + rate=22050, ibuf=20000) - + 3 modes of operation are supported: - - blocking - - non-blocking + - blocking + - non-blocking - uasyncio - + blocking:: - + num_written = audio_out.write(buf) # blocks until buf emptied num_read = audio_in.readinto(buf) # blocks until buf filled - + non-blocking:: - + audio_out.irq(i2s_callback) # i2s_callback is called when buf is emptied num_written = audio_out.write(buf) # returns immediately - + audio_in.irq(i2s_callback) # i2s_callback is called when buf is filled - num_read = audio_in.readinto(buf) # returns immediately - + num_read = audio_in.readinto(buf) # returns immediately + uasyncio:: - + swriter = uasyncio.StreamWriter(audio_out) swriter.write(buf) await swriter.drain() - + sreader = uasyncio.StreamReader(audio_in) num_read = await sreader.readinto(buf) - + Constructor ----------- .. class:: I2S(id, *, sck, ws, sd, mode, bits, format, rate, ibuf) Construct an I2S object of the given id: - - - ``id`` identifies a particular I2S bus. + + - ``id`` identifies a particular I2S bus. ``id`` is board and port specific: - + - PYBv1.0/v1.1: has one I2S bus with id=2. - - PYBD-SFxW: has two I2S buses with id=1 and id=2. - - ESP32: has two I2S buses with id=0 and id=1. - + - PYBD-SFxW: has two I2S buses with id=1 and id=2. + - ESP32: has two I2S buses with id=0 and id=1. + Keyword-only parameters that are supported on all ports: - + - ``sck`` is a pin object for the serial clock line - ``ws`` is a pin object for the word select line - ``sd`` is a pin object for the serial data line @@ -97,9 +97,9 @@ Constructor - ``format`` specifies channel format, STEREO or MONO - ``rate`` specifies audio sampling rate (samples/s) - ``ibuf`` specifies internal buffer length (bytes) - - For all ports, DMA runs continuously in the background and allows user applications to perform other operations while - sample data is transfered between the internal buffer and the I2S peripheral unit. + + For all ports, DMA runs continuously in the background and allows user applications to perform other operations while + sample data is transfered between the internal buffer and the I2S peripheral unit. Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method). @@ -109,37 +109,37 @@ Methods .. method:: I2S.init(sck, ...) see Constructor for argument descriptions - + .. method:: I2S.deinit() Deinitialize the I2S bus - + .. method:: I2S.readinto(buf) - Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. - "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, the left channel sample data is used. - Returns number of bytes read - + Returns number of bytes read + .. method:: I2S.write(buf) Write audio samples contained in ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. - "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, + "buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format, the sample data is written to both the right and left channels. - Returns number of bytes written - + Returns number of bytes written + .. method:: I2S.irq(handler) - Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method). + Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method). Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation. ``handler`` is called in the context of the MicroPython scheduler. - -.. staticmethod:: I2S.shift(buf, bits, shift) - bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample. - Positive for left shift, negative for right shift. +.. staticmethod:: I2S.shift(*, buf, bits, shift) + + bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample. + Positive for left shift, negative for right shift. Typically used for volume control. Each bit shift changes sample volume by 6dB. - + Constants --------- diff --git a/docs/library/machine.PWM.rst b/docs/library/machine.PWM.rst index f2273d8b4..4c72255d8 100644 --- a/docs/library/machine.PWM.rst +++ b/docs/library/machine.PWM.rst @@ -77,3 +77,34 @@ Methods With no arguments the pulse width in nanoseconds is returned. With a single *value* argument the pulse width is set to that value. + +Limitations of PWM +------------------ + +* Not all frequencies can be generated with absolute accuracy due to + the discrete nature of the computing hardware. Typically the PWM frequency + is obtained by dividing some integer base frequency by an integer divider. + For example, if the base frequency is 80MHz and the required PWM frequency is + 300kHz the divider must be a non-integer number 80000000 / 300000 = 266.67. + After rounding the divider is set to 267 and the PWM frequency will be + 80000000 / 267 = 299625.5 Hz, not 300kHz. If the divider is set to 266 then + the PWM frequency will be 80000000 / 266 = 300751.9 Hz, but again not 300kHz. + +* The duty cycle has the same discrete nature and its absolute accuracy is not + achievable. On most hardware platforms the duty will be applied at the next + frequency period. Therefore, you should wait more than "1/frequency" before + measuring the duty. + +* The frequency and the duty cycle resolution are usually interdependent. + The higher the PWM frequency the lower the duty resolution which is available, + and vice versa. For example, a 300kHz PWM frequency can have a duty cycle + resolution of 8 bit, not 16-bit as may be expected. In this case, the lowest + 8 bits of *duty_u16* are insignificant. So:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2) + + and:: + + pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255) + + will generate PWM with the same 50% duty cycle. diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst index f8e9e1054..32fa05b49 100644 --- a/docs/library/machine.Pin.rst +++ b/docs/library/machine.Pin.rst @@ -74,6 +74,8 @@ Constructors - ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as open-drain. Not all ports implement this mode. + - ``Pin.ANALOG`` - Pin is configured for analog input, see the :class:`ADC` class. + - ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be one of: @@ -247,6 +249,7 @@ not all constants are available on all ports. Pin.OPEN_DRAIN Pin.ALT Pin.ALT_OPEN_DRAIN + Pin.ANALOG Selects the pin mode. diff --git a/docs/library/machine.SD.rst b/docs/library/machine.SD.rst index d985db231..c736dc4d2 100644 --- a/docs/library/machine.SD.rst +++ b/docs/library/machine.SD.rst @@ -32,7 +32,7 @@ Constructors .. class:: SD(id,... ) - Create a SD card object. See ``init()`` for parameters if initialization. + Create a SD card object. See ``init()`` for parameters if initialization. Methods ------- diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst index 96fb5b01c..b07ad37d3 100644 --- a/docs/library/machine.SDCard.rst +++ b/docs/library/machine.SDCard.rst @@ -50,7 +50,7 @@ vary from platform to platform. - *mosi* can be used to specify an SPI mosi pin. - *cs* can be used to specify an SPI chip select pin. - + - *freq* selects the SD/MMC interface frequency in Hz (only supported on the ESP32). Implementation-specific details diff --git a/docs/library/machine.SPI.rst b/docs/library/machine.SPI.rst index 46ac2ec74..1116f0e8a 100644 --- a/docs/library/machine.SPI.rst +++ b/docs/library/machine.SPI.rst @@ -19,6 +19,42 @@ Software SPI is implemented by bit-banging and can be used on any pin but is not as efficient. These classes have the same methods available and differ primarily in the way they are constructed. +Example usage:: + + from machine import SPI, Pin + + spi = SPI(0, baudrate=400000) # Create SPI peripheral 0 at frequency of 400kHz. + # Depending on the use case, extra parameters may be required + # to select the bus characteristics and/or pins to use. + cs = Pin(4, mode=Pin.OUT, value=1) # Create chip-select on pin 4. + + try: + cs(0) # Select peripheral. + spi.write(b"12345678") # Write 8 bytes, and don't care about received data. + finally: + cs(1) # Deselect peripheral. + + try: + cs(0) # Select peripheral. + rxdata = spi.read(8, 0x42) # Read 8 bytes while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + rxdata = bytearray(8) + try: + cs(0) # Select peripheral. + spi.readinto(rxdata, 0x42) # Read 8 bytes inplace while writing 0x42 for each byte. + finally: + cs(1) # Deselect peripheral. + + txdata = b"12345678" + rxdata = bytearray(len(txdata)) + try: + cs(0) # Select peripheral. + spi.write_readinto(txdata, rxdata) # Simultaneously write and read bytes. + finally: + cs(1) # Deselect peripheral. + Constructors ------------ diff --git a/docs/library/machine.Timer.rst b/docs/library/machine.Timer.rst index 77a549b40..424a49bcb 100644 --- a/docs/library/machine.Timer.rst +++ b/docs/library/machine.Timer.rst @@ -27,11 +27,12 @@ instead of this class. Constructors ------------ -.. class:: Timer(id, ...) +.. class:: Timer(id, /, ...) - Construct a new timer object of the given id. Id of -1 constructs a + Construct a new timer object of the given ``id``. ``id`` of -1 constructs a virtual timer (if supported by a board). - + ``id`` shall not be passed as a keyword argument. + See ``init`` for parameters of initialisation. Methods @@ -41,8 +42,14 @@ Methods Initialise the timer. Example:: - tim.init(period=100) # periodic with 100ms period - tim.init(mode=Timer.ONE_SHOT, period=1000) # one shot firing after 1000ms + def mycallback(t): + pass + + # periodic with 100ms period + tim.init(period=100, callback=mycallback) + + # one shot firing after 1000ms + tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback) Keyword arguments: @@ -53,6 +60,14 @@ Methods - ``Timer.PERIODIC`` - The timer runs periodically at the configured frequency of the channel. + - ``period`` - The timer period, in milliseconds. + + - ``callback`` - The callable to call upon expiration of the timer period. + The callback must take one argument, which is passed the Timer object. + The ``callback`` argument shall be specified. Otherwise an exception + will occurr upon timer expiration: + ``TypeError: 'NoneType' object isn't callable`` + .. method:: Timer.deinit() Deinitialises the timer. Stops the timer, and disables the timer peripheral. diff --git a/docs/library/machine.TimerWiPy.rst b/docs/library/machine.TimerWiPy.rst index 39afc23bc..f8c8bb29d 100644 --- a/docs/library/machine.TimerWiPy.rst +++ b/docs/library/machine.TimerWiPy.rst @@ -50,9 +50,9 @@ Methods - ``mode`` can be one of: - - ``TimerWiPy.ONE_SHOT`` - The timer runs once until the configured + - ``TimerWiPy.ONE_SHOT`` - The timer runs once until the configured period of the channel expires. - - ``TimerWiPy.PERIODIC`` - The timer runs periodically at the configured + - ``TimerWiPy.PERIODIC`` - The timer runs periodically at the configured frequency of the channel. - ``TimerWiPy.PWM`` - Output a PWM signal on a pin. @@ -74,7 +74,7 @@ Methods The operating mode is is the one configured to the Timer object that was used to create the channel. - - ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``. + - ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``. If the width is 32-bit then it **must be** ``TIMER.A | TIMER.B``. Keyword only arguments: diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index 2eb2e20cb..8fb42cfe8 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -64,7 +64,7 @@ Methods - *timeout_char* specifies the time to wait between characters (in ms). - *invert* specifies which lines to invert. - *flow* specifies which hardware flow control signals to use. The value - is a bitmask. + is a bitmask. - ``0`` will ignore hardware flow control signals. - ``UART.RTS`` will enable receive flow control by using the RTS output pin to diff --git a/docs/library/machine.WDT.rst b/docs/library/machine.WDT.rst index 612f23ba3..3c799583e 100644 --- a/docs/library/machine.WDT.rst +++ b/docs/library/machine.WDT.rst @@ -24,7 +24,7 @@ Constructors Create a WDT object and start it. The timeout must be given in milliseconds. Once it is running the timeout cannot be changed and the WDT cannot be stopped either. - + Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout cannot be specified, it is determined by the underlying system. diff --git a/docs/library/machine.rst b/docs/library/machine.rst index c2a6b3900..5f45168ed 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -203,7 +203,7 @@ Classes machine.UART.rst machine.SPI.rst machine.I2C.rst - machine.I2S.rst + machine.I2S.rst machine.RTC.rst machine.Timer.rst machine.WDT.rst diff --git a/docs/library/os.rst b/docs/library/os.rst index a1eae4f24..19652ee2b 100644 --- a/docs/library/os.rst +++ b/docs/library/os.rst @@ -314,6 +314,12 @@ that the block device supports the extended interface. ``ioctl(6, ...)`` must also be intercepted. The need for others is hardware dependent. + Prior to any call to ``writeblocks(block, ...)`` littlefs issues + ``ioctl(6, block)``. This enables a device driver to erase the block + prior to a write if the hardware requires it. Alternatively a driver + might intercept ``ioctl(6, block)`` and return 0 (success). In this case + the driver assumes responsibility for detecting the need for erasure. + 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 diff --git a/docs/library/pyb.Pin.rst b/docs/library/pyb.Pin.rst index 6465653f7..97dfbffbc 100644 --- a/docs/library/pyb.Pin.rst +++ b/docs/library/pyb.Pin.rst @@ -120,7 +120,7 @@ Methods - *value* if not None will set the port output value before enabling the pin. - *alt* can be used when mode is ``Pin.AF_PP`` or ``Pin.AF_OD`` to set the - index or name of one of the alternate functions associated with a pin. + index or name of one of the alternate functions associated with a pin. This arg was previously called *af* which can still be used if needed. Returns: ``None``. diff --git a/docs/library/random.rst b/docs/library/random.rst new file mode 100644 index 000000000..dd8b47c80 --- /dev/null +++ b/docs/library/random.rst @@ -0,0 +1,82 @@ +:mod:`random` -- generate random numbers +======================================== + +.. module:: random + :synopsis: random numbers + +This module implements a pseudo-random number generator (PRNG). + +|see_cpython_module| :mod:`python:random` . + +.. note:: + + The following notation is used for intervals: + + - () are open interval brackets and do not include their endpoints. + For example, (0, 1) means greater than 0 and less than 1. + In set notation: (0, 1) = {x | 0 < x < 1}. + + - [] are closed interval brackets which include all their limit points. + For example, [0, 1] means greater than or equal to 0 and less than + or equal to 1. + In set notation: [0, 1] = {x | 0 <= x <= 1}. + +.. note:: + + The :func:`randrange`, :func:`randint` and :func:`choice` functions are only + available if the ``MICROPY_PY_URANDOM_EXTRA_FUNCS`` configuration option is + enabled. + + +Functions for integers +---------------------- + +.. function:: getrandbits(n) + + Return an integer with *n* random bits (0 <= n <= 32). + +.. function:: randint(a, b) + + Return a random integer in the range [*a*, *b*]. + +.. function:: randrange(stop) + randrange(start, stop) + randrange(start, stop[, step]) + + The first form returns a random integer from the range [0, *stop*). + The second form returns a random integer from the range [*start*, *stop*). + The third form returns a random integer from the range [*start*, *stop*) in + steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will + return odd numbers between 1 and 9 inclusive. + + +Functions for floats +-------------------- + +.. function:: random() + + Return a random floating point number in the range [0.0, 1.0). + +.. function:: uniform(a, b) + + Return a random floating point number N such that *a* <= N <= *b* for *a* <= *b*, + and *b* <= N <= *a* for *b* < *a*. + + +Other Functions +--------------- + +.. function:: seed(n=None, /) + + Initialise the random number generator module with the seed *n* which should + be an integer. When no argument (or ``None``) is passed in it will (if + supported by the port) initialise the PRNG with a true random number + (usually a hardware generated random number). + + The ``None`` case only works if ``MICROPY_PY_URANDOM_SEED_INIT_FUNC`` is + enabled by the port, otherwise it raises ``ValueError``. + +.. function:: choice(sequence) + + Chooses and returns one item at random from *sequence* (tuple, list or + any object that supports the subscript operation). diff --git a/docs/library/rp2.rst b/docs/library/rp2.rst index 5d168bce2..05d3b80f3 100644 --- a/docs/library/rp2.rst +++ b/docs/library/rp2.rst @@ -58,7 +58,7 @@ For running PIO programs, see :class:`rp2.StateMachine`. combined into a single 8-word FIFO for one direction only. The options are `PIO.JOIN_NONE`, `PIO.JOIN_RX` and `PIO.JOIN_TX`. -.. function:: asm_pio_encode(instr, sideset_count) +.. function:: asm_pio_encode(instr, sideset_count, sideset_opt=False) Assemble a single PIO instruction. You usually want to use `asm_pio()` instead. @@ -72,6 +72,158 @@ For running PIO programs, see :class:`rp2.StateMachine`. an error assembling a PIO program. +PIO assembly language instructions +---------------------------------- + +PIO state machines are programmed in a custom assembly language with nine core +PIO-machine instructions. In MicroPython, PIO assembly routines are written as +a Python function with the decorator ``@rp2.asm_pio()``, and they use Python +syntax. Such routines support standard Python variables and arithmetic, as well +as the following custom functions that encode PIO instructions and direct the +assembler. See sec 3.4 of the RP2040 datasheet for further details. + +wrap_target() + Specify the location where execution continues after program wrapping. + By default this is the start of the PIO routine. + +wrap() + Specify the location where the program finishes and wraps around. + If this directive is not used then it is added automatically at the end of + the PIO routine. Wrapping does not cost any execution cycles. + +label(label) + Define a label called *label* at the current location. *label* can be a + string or integer. + +word(instr, label=None) + Insert an arbitrary 16-bit word in the assembled output. + + - *instr*: the 16-bit value + - *label*: if given, look up the label and logical-or the label's value with + *instr* + +jmp(...) + This instruction takes two forms: + + jmp(label) + - *label*: label to jump to unconditionally + + jmp(cond, label) + - *cond*: the condition to check, one of: + + - ``not_x``, ``not_y``: true if register is zero + - ``x_dec``, ``y_dec``: true if register is non-zero, and do post + decrement + - ``x_not_y``: true if X is not equal to Y + - ``pin``: true if the input pin is set + - ``not_osre``: true if OSR is not empty (hasn't reached its + threshold) + + - *label*: label to jump to if condition is true + +wait(polarity, src, index) + Block, waiting for high/low on a pin or IRQ line. + + - *polarity*: 0 or 1, whether to wait for a low or high value + - *src*: one of: ``gpio`` (absolute pin), ``pin`` (pin relative to + StateMachine's ``in_base`` argument), ``irq`` + - *index*: 0-31, the index for *src* + +in_(src, bit_count) + Shift data in from *src* to ISR. + + - *src*: one of: ``pins``, ``x``, ``y``, ``null``, ``isr``, ``osr`` + - *bit_count*: number of bits to shift in (1-32) + +out(dest, bit_count) + Shift data out from OSR to *dest*. + + - *dest*: one of: ``pins``, ``x``, ``y``, ``pindirs``, ``pc``, ``isr``, + ``exec`` + - *bit_count*: number of bits to shift out (1-32) + +push(...) + Push ISR to the RX FIFO, then clear ISR to zero. + This instruction takes the following forms: + + - push() + - push(block) + - push(noblock) + - push(iffull) + - push(iffull, block) + - push(iffull, noblock) + + If ``block`` is used then the instruction stalls if the RX FIFO is full. + The default is to block. If ``iffull`` is used then it only pushes if the + input shift count has reached its threshold. + +pull(...) + Pull from the TX FIFO into OSR. + This instruction takes the following forms: + + - pull() + - pull(block) + - pull(noblock) + - pull(ifempty) + - pull(ifempty, block) + - pull(ifempty, noblock) + + If ``block`` is used then the instruction stalls if the TX FIFO is empty. + The default is to block. If ``ifempty`` is used then it only pulls if the + output shift count has reached its threshold. + +mov(dest, src) + Move into *dest* the value from *src*. + + - *dest*: one of: ``pins``, ``x``, ``y``, ``exec``, ``pc``, ``isr``, ``osr`` + - *src*: one of: ``pins``, ``x``, ``y``, ``null``, ``status``, ``isr``, + ``osr``; this argument can be optionally modified by wrapping it in + ``invert()`` or ``reverse()`` (but not both together) + +irq(...) + Set or clear an IRQ flag. + This instruction takes two forms: + + irq(index) + - *index*: 0-7, or ``rel(0)`` to ``rel(7)`` + + irq(mode, index) + - *mode*: one of: ``block``, ``clear`` + - *index*: 0-7, or ``rel(0)`` to ``rel(7)`` + + If ``block`` is used then the instruction stalls until the flag is cleared + by another entity. If ``clear`` is used then the flag is cleared instead of + being set. Relative IRQ indices add the state machine ID to the IRQ index + with modulo-4 addition. IRQs 0-3 are visible from to the processor, 4-7 are + internal to the state machines. + +set(dest, data) + Set *dest* with the value *data*. + + - *dest*: ``pins``, ``x``, ``y``, ``pindirs`` + - *data*: value (0-31) + +nop() + This is a pseudoinstruction that assembles to ``mov(y, y)`` and has no side + effect. + +.side(value) + This is a modifier which can be applied to any instruction, and is used to + control side-set pin values. + + - *value*: the value (bits) to output on the side-set pins + +.delay(value) + This is a modifier which can be applied to any instruction, and specifies + how many cycles to delay for after the instruction executes. + + - *value*: cycles to delay, 0-31 (maximum value reduced if side-set pins are + used) + +[value] + This is a modifier and is equivalent to ``.delay(value)``. + + Classes ------- diff --git a/docs/library/stm.rst b/docs/library/stm.rst new file mode 100644 index 000000000..a181d6044 --- /dev/null +++ b/docs/library/stm.rst @@ -0,0 +1,104 @@ +.. currentmodule:: stm + +:mod:`stm` --- functionality specific to STM32 MCUs +=================================================== + +.. module:: stm + :synopsis: functionality specific to STM32 MCUs + +This module provides functionality specific to STM32 microcontrollers, including +direct access to peripheral registers. + +Memory access +------------- + +The module exposes three objects used for raw memory access. + +.. data:: mem8 + + Read/write 8 bits of memory. + +.. data:: mem16 + + Read/write 16 bits of memory. + +.. data:: mem32 + + Read/write 32 bits of memory. + +Use subscript notation ``[...]`` to index these objects with the address of +interest. + +These memory objects can be used in combination with the peripheral register +constants to read and write registers of the MCU hardware peripherals, as well +as all other areas of address space. + + +Peripheral register constants +----------------------------- + +The module defines constants for registers which are generated from CMSIS header +files, and the constants available depend on the microcontroller series that is +being compiled for. Examples of some constants include: + +.. data:: GPIOA + + Base address of the GPIOA peripheral. + +.. data:: GPIOB + + Base address of the GPIOB peripheral. + +.. data:: GPIO_BSRR + + Offset of the GPIO bit set/reset register. + +.. data:: GPIO_IDR + + Offset of the GPIO input data register. + +.. data:: GPIO_ODR + + Offset of the GPIO output data register. + +Constants that are named after a peripheral, like ``GPIOA``, are the absolute +address of that peripheral. Constants that have a prefix which is the name of a +peripheral, like ``GPIO_BSRR``, are relative offsets of the register. Accessing +peripheral registers requires adding the absolute base address of the peripheral +and the relative register offset. For example ``GPIOA + GPIO_BSRR`` is the +full, absolute address of the ``GPIOA->BSRR`` register. + +Example use: + +.. code-block:: python3 + + # set PA2 high + stm.mem32[stm.GPIOA + stm.GPIO_BSRR] = 1 << 2 + + # read PA3 + value = (stm.mem32[stm.GPIOA + stm.GPIO_IDR] >> 3) & 1 + + +Functions specific to STM32WBxx MCUs +------------------------------------ + +These functions are available on STM32WBxx microcontrollers, and interact with +the second CPU, the RF core. + +.. function:: rfcore_status() + + Returns the status of the second CPU as an integer (the first word of device + info table). + +.. function:: rfcore_fw_version(id) + + Get the version of the firmware running on the second CPU. Pass in 0 for + *id* to get the FUS version, and 1 to get the WS version. + + Returns a 5-tuple with the full version number. + +.. function:: rfcore_sys_hci(ogf, ocf, data, timeout_ms=0) + + Execute a HCI command on the SYS channel. The execution is synchronous. + + Returns a bytes object with the result of the SYS command. diff --git a/docs/library/sys.rst b/docs/library/sys.rst index 24f9e353b..d36394c88 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -43,6 +43,15 @@ Functions positional; further arguments are not supported. CPython-compatible ``traceback`` module can be found in `micropython-lib`. +.. function:: settrace(tracefunc) + + Enable tracing of bytecode execution. For details see the `CPython + documentaion `_. + + This function requires a custom MicroPython build as it is typically not + present in pre-built firmware (due to it affecting performance). The relevant + configuration option is *MICROPY_PY_SYS_SETTRACE*. + Constants --------- @@ -106,6 +115,14 @@ Constants A mutable list of directories to search for imported modules. + .. admonition:: Difference to CPython + :class: attention + + On MicroPython, an entry with the value ``".frozen"`` will indicate that import + should search :term:`frozen modules ` at that point in the search. + If no frozen module is found then search will *not* look for a directory called + ``.frozen``, instead it will continue with the next entry in ``sys.path``. + .. data:: platform The platform that MicroPython is running on. For OS/RTOS ports, this is diff --git a/docs/library/uasyncio.rst b/docs/library/uasyncio.rst index 11b9c6aee..1fc8b53db 100644 --- a/docs/library/uasyncio.rst +++ b/docs/library/uasyncio.rst @@ -68,11 +68,13 @@ Additional functions .. function:: wait_for(awaitable, timeout) Wait for the *awaitable* to complete, but cancel it if it takes longer - that *timeout* seconds. If *awaitable* is not a task then a task will be + than *timeout* seconds. If *awaitable* is not a task then a task will be created from it. If a timeout occurs, it cancels the task and raises ``asyncio.TimeoutError``: - this should be trapped by the caller. + this should be trapped by the caller. The task receives + ``asyncio.CancelledError`` which may be ignored or trapped using ``try...except`` + or ``try...finally`` to run cleanup code. Returns the return value of *awaitable*. @@ -106,8 +108,9 @@ class Task .. method:: Task.cancel() - Cancel the task by injecting a ``CancelledError`` into it. The task may - or may not ignore this exception. + Cancel the task by injecting ``asyncio.CancelledError`` into it. The task may + ignore this exception. Cleanup code may be run by trapping it, or via + ``try ... finally``. class Event ----------- diff --git a/docs/make.bat b/docs/make.bat index c09487fb7..2a9e670e4 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -5,7 +5,7 @@ REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) -set BUILDDIR=_build +set BUILDDIR=build set SPHINXOPTS=-W --keep-going set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index ed56811dd..62157bff0 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -225,20 +225,20 @@ I2S bus See :ref:`machine.I2S `. :: from machine import I2S, Pin - + i2s = I2S(2, sck=Pin('Y6'), ws=Pin('Y5'), sd=Pin('Y8'), mode=I2S.TX, bits=16, format=I2S.STEREO, rate=44100, ibuf=40000) # create I2S object i2s.write(buf) # write buffer of audio samples to I2S device - + i2s = I2S(1, sck=Pin('X5'), ws=Pin('X6'), sd=Pin('Y4'), mode=I2S.RX, bits=16, format=I2S.MONO, rate=22050, ibuf=40000) # create I2S object i2s.readinto(buf) # fill buffer with audio samples from I2S device - -The I2S class is currently available as a Technical Preview. During the preview period, feedback from + +The I2S class is currently available as a Technical Preview. During the preview period, feedback from users is encouraged. Based on this feedback, the I2S class API and implementation may be changed. -PYBv1.0/v1.1 has one I2S bus with id=2. -PYBD-SFxW has two I2S buses with id=1 and id=2. -I2S is shared with SPI. - +PYBv1.0/v1.1 has one I2S bus with id=2. +PYBD-SFxW has two I2S buses with id=1 and id=2. +I2S is shared with SPI. + CAN bus (controller area network) --------------------------------- diff --git a/docs/pyboard/tutorial/accel.rst b/docs/pyboard/tutorial/accel.rst index 58170e74f..dff71f2ee 100644 --- a/docs/pyboard/tutorial/accel.rst +++ b/docs/pyboard/tutorial/accel.rst @@ -29,7 +29,7 @@ We will start by using the accelerometer to turn on a light if it is not flat. : while True: x = accel.x() - if abs(x) > SENSITIVITY: + if abs(x) > SENSITIVITY: light.on() else: light.off() @@ -61,7 +61,7 @@ use the ``y()`` value and more LEDs we can turn the pyboard into a spirit level. while True: x = accel.x() - if x > SENSITIVITY: + if x > SENSITIVITY: xlights[0].on() xlights[1].off() elif x < -SENSITIVITY: @@ -72,7 +72,7 @@ use the ``y()`` value and more LEDs we can turn the pyboard into a spirit level. xlights[1].off() y = accel.y() - if y > SENSITIVITY: + if y > SENSITIVITY: ylights[0].on() ylights[1].off() elif y < -SENSITIVITY: diff --git a/docs/pyboard/tutorial/leds.rst b/docs/pyboard/tutorial/leds.rst index 05f3b619e..63acc63ce 100644 --- a/docs/pyboard/tutorial/leds.rst +++ b/docs/pyboard/tutorial/leds.rst @@ -47,7 +47,7 @@ Here, n keeps track of the current LED and every time the loop is executed we cy One problem you might find is that if you stop the script and then start it again that the LEDs are stuck on from the previous run, ruining our carefully choreographed disco. We can fix this by turning all the LEDs off when we initialise the script and then using a try/finally block. When you press CTRL-C, MicroPython generates a VCPInterrupt exception. Exceptions normally mean something has gone wrong and you can use a try: command to "catch" an exception. In this case it is just the user interrupting the script, so we don't need to catch the error but just tell MicroPython what to do when we exit. The finally block does this, and we use it to make sure all the LEDs are off. The full code is:: leds = [pyb.LED(i) for i in range(1,5)] - for l in leds: + for l in leds: l.off() n = 0 diff --git a/docs/pyboard/tutorial/repl.rst b/docs/pyboard/tutorial/repl.rst index 973d1846a..b28d9cd57 100644 --- a/docs/pyboard/tutorial/repl.rst +++ b/docs/pyboard/tutorial/repl.rst @@ -73,7 +73,7 @@ indicate that you should type the text after it at the prompt. In the end, once you have entered the text ``print("hello pyboard!")`` and pressed Enter, the output on your screen should look like it does above. -If you already know some python you can now try some basic commands here. +If you already know some python you can now try some basic commands here. If any of this is not working you can try either a hard reset or a soft reset; see below. diff --git a/docs/pyboard/tutorial/reset.rst b/docs/pyboard/tutorial/reset.rst index 0cd5ac21c..59a3cd82a 100644 --- a/docs/pyboard/tutorial/reset.rst +++ b/docs/pyboard/tutorial/reset.rst @@ -21,7 +21,7 @@ To enter safe mode, do the following steps: 4. The LEDs will then cycle green to orange to green+orange and back again. 5. Keep holding down USR until *only the orange LED is lit*, and then let go of the USR switch. -6. The orange LED should flash quickly 4 times, and then turn off. +6. The orange LED should flash quickly 4 times, and then turn off. 7. You are now in safe mode. In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so diff --git a/docs/pyboard/tutorial/usb_mouse.rst b/docs/pyboard/tutorial/usb_mouse.rst index 8166946ec..d05b16ed5 100644 --- a/docs/pyboard/tutorial/usb_mouse.rst +++ b/docs/pyboard/tutorial/usb_mouse.rst @@ -8,8 +8,8 @@ To do this we must first edit the ``boot.py`` file to change the USB configuration. If you have not yet touched your ``boot.py`` file then it will look something like this:: - # boot.py -- run on boot-up - # can run arbitrary Python, but best to keep it minimal + # boot.py -- run on boot to configure USB and filesystem + # Put app code in main.py import pyb #pyb.main('main.py') # main script to run after this one diff --git a/docs/reference/asm_thumb2_hints_tips.rst b/docs/reference/asm_thumb2_hints_tips.rst index 062a3c844..361e44380 100644 --- a/docs/reference/asm_thumb2_hints_tips.rst +++ b/docs/reference/asm_thumb2_hints_tips.rst @@ -3,7 +3,7 @@ Hints and tips The following are some examples of the use of the inline assembler and some information on how to work around its limitations. In this document the term -"assembler function" refers to a function declared in Python with the +"assembler function" refers to a function declared in Python with the ``@micropython.asm_thumb`` decorator, whereas "subroutine" refers to assembler code called from within an assembler function. @@ -106,8 +106,8 @@ function can return multiple values by assigning them to array elements. Assembler functions have no means of determining the length of an array: this will need to be passed to the function. -This use of arrays can be extended to enable more than three arrays to be used. -This is done using indirection: the ``uctypes`` module supports ``addressof()`` +This use of arrays can be extended to enable more than three arrays to be used. +This is done using indirection: the ``uctypes`` module supports ``addressof()`` which will return the address of an array passed as its argument. Thus you can populate an integer array with the addresses of other arrays: diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index 2a5f9d7fd..816a20f9d 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -144,7 +144,7 @@ store constant data: As in the string example, at runtime a reference to the arbitrarily large integer is assigned to the variable ``bar``. That reference occupies a -single machine word. +single machine word. It might be expected that tuples of integers could be employed for the purpose of storing constant data with minimal RAM use. With the current compiler this diff --git a/docs/reference/filesystem.rst b/docs/reference/filesystem.rst index 114e59735..ca9e56344 100644 --- a/docs/reference/filesystem.rst +++ b/docs/reference/filesystem.rst @@ -219,15 +219,6 @@ resistant to filesystem corruption. 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:: # ESP8266 and ESP32 @@ -243,6 +234,27 @@ To format the entire flash using littlefs v2:: os.mount(pyb.Flash(start=0), '/flash') os.chdir('/flash') +A littlefs filesystem can be still be accessed on a PC over USB MSC using the +`littlefs FUSE driver`_. Note that you must specify both the ``--block_size`` +and ``--block_count`` options to override the defaults. For example (after +building the littlefs-fuse executable):: + + $ ./lfs --block_size=4096 --block_count=512 -o allow_other /dev/sdb1 mnt + +This will allow the board's littlefs filesystem to be accessed at the ``mnt`` +directory. To get the correct values of ``block_size`` and ``block_count`` use:: + + import pyb + f = pyb.Flash(start=0) + f.ioctl(1, 1) # initialise flash in littlefs raw-block mode + block_count = f.ioctl(4, 0) + block_size = f.ioctl(5, 0) + +.. _littlefs FUSE driver: https://github.com/littlefs-project/littlefs-fuse +.. _Littlefs: https://github.com/littlefs-project/littlefs +.. _littlefs issue 295: https://github.com/littlefs-project/littlefs/issues/295 +.. _littlefs issue 347: https://github.com/littlefs-project/littlefs/issues/347 + Hybrid (STM32) ~~~~~~~~~~~~~~ diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 8cd5f03df..8ac92c22e 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -21,10 +21,12 @@ implementation and the best practices to use them. glossary.rst repl.rst + mpremote.rst mpyfiles.rst isr_rules.rst speed_python.rst constrained.rst + manifest.rst packages.rst asm_thumb2_index.rst filesystem.rst diff --git a/docs/reference/manifest.rst b/docs/reference/manifest.rst new file mode 100644 index 000000000..078c4c7cf --- /dev/null +++ b/docs/reference/manifest.rst @@ -0,0 +1,145 @@ +MicroPython manifest files +========================== + +When building firmware for a device the following components are included in +the compilation process: + +- the core MicroPython virtual machine and runtime +- port-specific system code and drivers to interface with the + microcontroller/device that the firmware is targeting +- standard built-in modules, like ``sys`` +- extended built-in modules, like ``json`` and ``machine`` +- extra modules written in C/C++ +- extra modules written in Python + +All the modules included in the firmware are available via ``import`` from +Python code. The extra modules written in Python that are included in a build +(the last point above) are called *frozen modules*, and are specified by a +``manifest.py`` file. Changing this manifest requires rebuilding the firmware. + +It's also possible to add additional modules to the filesystem of the device +once it is up and running. Adding and removing modules to/from the filesystem +does not require rebuilding the firmware so is a simpler process than rebuilding +firmware. The benefit of using a manifest is that frozen modules are more +efficient: they are faster to import and take up less RAM once imported. + +MicroPython manifest files are Python files and can contain arbitrary Python +code. There are also a set of commands (predefined functions) which are used +to specify the Python source files to include. These commands are described +below. + +Freezing source code +-------------------- + +.. function:: freeze(path, script=None, opt=0) + + Freeze the input specified by *path*, 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 begin searching + for files. When importing the resulting frozen modules, the name of the + module will start after *path*, i.e. *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 + iterable (with the same *path* and *opt* passed through). + + If *script* is a string then it specifies the file or directory to freeze, + and can include extra directories before the file or last directory. The + file or directory will be searched for in *path*. If *script* is a + directory then all files in that directory will be frozen. + + *opt* is the optimisation level to pass to mpy-cross when compiling ``.py`` + to ``.mpy``. + +.. function:: freeze_as_str(path) + + Freeze the given *path* and all ``.py`` scripts within it as a string, which + will be compiled upon import. + +.. function:: freeze_as_mpy(path, script=None, opt=0) + + Freeze the input by first compiling the ``.py`` scripts to ``.mpy`` files, + then freezing the resulting ``.mpy`` files. See ``freeze()`` for further + details on the arguments. + +.. function:: freeze_mpy(path, script=None, opt=0) + + Freeze the input, which must be ``.mpy`` files that are frozen directly. + See ``freeze()`` for further details on the arguments. + + +Including other manifest files +------------------------------ + +.. function:: include(manifest, **kwargs) + + Include another manifest. + + The *manifest* argument can be a string (filename) or an iterable of + strings. + + Relative paths are resolved with respect to the current manifest file. + + Optional *kwargs* can be provided which will be available to the included + script via the *options* variable. + + For example: + + .. code-block:: python3 + + include("path.py", extra_features=True) + + then in path.py: + + .. code-block:: python3 + + options.defaults(standard_features=True) + # freeze minimal modules. + if options.standard_features: + # freeze standard modules. + if options.extra_features: + # freeze extra modules. + + +Examples +-------- + +To freeze a single file which is available as ``import mydriver``, use: + +.. code-block:: python3 + + freeze(".", "mydriver.py") + +To freeze a set of files which are available as ``import test1`` and +``import test2``, and which are compiled with optimisation level 3, use: + +.. code-block:: python3 + + freeze("/path/to/tests", ("test1.py", "test2.py"), opt=3) + +To freeze a module which can be imported as ``import mymodule``, use: + +.. code-block:: python3 + + freeze( + "../relative/path", + ( + "mymodule/__init__.py", + "mymodule/core.py", + "mymodule/extra.py", + ), + ) + +To include a manifest from the MicroPython repository, use: + +.. code-block:: python3 + + include("$(MPY_DIR)/extmod/uasyncio/manifest.py") diff --git a/docs/reference/mpremote.rst b/docs/reference/mpremote.rst new file mode 100644 index 000000000..7a7d787a5 --- /dev/null +++ b/docs/reference/mpremote.rst @@ -0,0 +1,196 @@ +MicroPython remote control: mpremote +==================================== + +The ``mpremote`` command line tool provides an integrated set of utilities to +remotely interact with and automate a MicroPython device over a serial +connection. + +To use mpremote install it via ``pip``: + +.. code-block:: bash + + $ pip install mpremote + +The simplest way to use this tool is just by invoking it without any arguments: + +.. code-block:: bash + + mpremote + +This command automatically detects and connects to the first available serial +device and provides an interactive REPL. Serial ports are opened in exclusive +mode, so running a second (or third, etc) instance of ``mpremote`` will connect +to subsequent serial devices, if any are available. + + +Commands +-------- + +For REPL access, running ``mpremote`` without any arguments is usually all that +is needed. ``mpremote`` also supports a set of commands given at the command +line which will perform various actions on remote MicroPython devices. + +The full list of supported commands are: + +- connect to a specified device via a device-name shortcut: + + .. code-block:: bash + + $ mpremote + +- connect to specified device via name: + + .. code-block:: bash + + $ mpremote connect + + ```` may be one of: + + - ``list``: list available devices + - ``auto``: connect to the first available device + - ``id:``: connect to the device with USB serial number + ```` (the second entry in the output from the ``connect list`` + command) + - ``port:``: connect to the device with the given path + - any valid device name/path, to connect to that device + +- disconnect current device: + + .. code-block:: bash + + $ mpremote disconnect + +- enter the REPL on the connected device: + + .. code-block:: bash + + $ mpremote repl [options] + + Options are: + + - ``--capture ``, to capture output of the REPL session to the given + file + - ``--inject-code ``, to specify characters to inject at the REPL when + Ctrl-J is pressed + - ``--inject-file ``, to specify a file to inject at the REPL when + Ctrl-K is pressed + +- evaluate and print the result of a Python expression: + + .. code-block:: bash + + $ mpremote eval + +- execute the given Python code: + + .. code-block:: bash + + $ mpremote exec + +- run a script from the local filesystem: + + .. code-block:: bash + + $ mpremote run + +- execute filesystem commands on the device: + + .. code-block:: bash + + $ mpremote fs + + ```` may be: + + - ``cat `` to show the contents of a file or files on the device + - ``ls`` to list the current directory + - ``ls `` to list the given directories + - ``cp [-r] `` to copy files; use ":" as a prefix to specify + a file on the device + - ``rm `` to remove files on the device + - ``mkdir `` to create directories on the device + - ``rmdir `` to remove directories on the device + +- mount the local directory on the remote device: + + .. code-block:: bash + + $ mpremote mount + +Multiple commands can be specified and they will be run sequentially. +Connection and disconnection will be done automatically at the start and end of +the execution of the tool, if such commands are not explicitly given. Automatic +connection will search for the first available serial device. If no action is +specified then the REPL will be entered. + +Shortcuts +--------- + +Shortcuts can be defined using the macro system. Built-in shortcuts are:: + +- ``devs``: list available devices (shortcut for ``connect list``) + +- ``a0``, ``a1``, ``a2``, ``a3``: connect to /dev/ttyACM? + +- ``u0``, ``u1``, ``u2``, ``u3``: connect to /dev/ttyUSB? + +- ``c0``, ``c1``, ``c2``, ``c3``: connect to COM? + +- ``cat``, ``ls``, ``cp``, ``rm``, ``mkdir``, ``rmdir``, ``df``: filesystem + commands + +- ``reset``: reset the device + +- ``bootloader``: make the device enter its bootloader + +Any user configuration, including user-defined shortcuts, can be placed in the file +``.config/mpremote/config.py``. For example: + +.. code-block:: python3 + + commands = { + "c33": "connect id:334D335C3138", + "bl": "bootloader", + "double x=4": "eval x*2", # x is an argument, with default 4 + "wl_scan": ["exec", """ + import network + wl = network.WLAN() + wl.active(1) + for ap in wl.scan(): + print(ap) + """,], + "test": ["mount", ".", "exec", "import test"], + } + + +Examples +-------- + +.. code-block:: bash + + mpremote + + mpremote a1 + + mpremote connect /dev/ttyUSB0 repl + + mpremote ls + + mpremote a1 ls + + mpremote exec "import micropython; micropython.mem_info()" + + mpremote eval 1/2 eval 3/4 + + mpremote mount . + + mpremote mount . exec "import local_script" + + mpremote ls + + mpremote cat boot.py + + mpremote cp :main.py . + + mpremote cp main.py : + + mpremote cp -r dir/ : diff --git a/docs/reference/mpyfiles.rst b/docs/reference/mpyfiles.rst index 4791784ac..6ba7389cf 100644 --- a/docs/reference/mpyfiles.rst +++ b/docs/reference/mpyfiles.rst @@ -66,8 +66,6 @@ If importing an .mpy file fails then try the following: 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() diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index 85e956e8e..834a53b0a 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -36,7 +36,7 @@ Algorithms ~~~~~~~~~~ The most important aspect of designing any routine for performance is ensuring that -the best algorithm is employed. This is a topic for textbooks rather than for a +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. @@ -210,7 +210,7 @@ no adaptation (but see below). It is invoked by means of a function decorator: buf = self.linebuf # Cached object # code -There are certain limitations in the current implementation of the native code emitter. +There are certain limitations in the current implementation of the native code emitter. * Context managers are not supported (the ``with`` statement). * Generators are not supported. @@ -222,7 +222,7 @@ increase in compiled code size. The Viper code emitter ---------------------- -The optimisations discussed above involve standards-compliant Python code. The +The optimisations discussed above involve standards-compliant Python code. The Viper code emitter is not fully compliant. It supports special Viper native data types in pursuit of performance. Integer processing is non-compliant because it uses machine words: arithmetic on 32 bit hardware is performed modulo 2**32. @@ -237,7 +237,7 @@ bit manipulations. It is invoked using a decorator: def foo(self, arg: int) -> int: # code -As the above fragment illustrates it is beneficial to use Python type hints to assist the Viper optimiser. +As the above fragment illustrates it is beneficial to use Python type hints to assist the Viper optimiser. Type hints provide information on the data types of arguments and of the return value; these are a standard Python language feature formally defined here `PEP0484 `_. Viper supports its own set of types namely ``int``, ``uint`` (unsigned integer), ``ptr``, ``ptr8``, diff --git a/docs/rp2/general.rst b/docs/rp2/general.rst index 7042d0d25..9a31d2067 100644 --- a/docs/rp2/general.rst +++ b/docs/rp2/general.rst @@ -22,9 +22,9 @@ QFN-56 SMD package. The key features include: firmware from either the external flash memory or USB bus into internal SRAM) * QSPI bus controller, which supports up to 16 MB of external Flash memory -* On-chip programmable LDO togenerate core voltage +* On-chip programmable LDO to generate core voltage * 2 on-chip PLLs to generate USB and core clocks -* 30 GPIOpins, of which 4 can optionally be used as analog inputs +* 30 GPIO pins, of which 4 can optionally be used as analog inputs The peripherals include: diff --git a/docs/rp2/quickref.rst b/docs/rp2/quickref.rst index ac9cdb86c..4824f390e 100644 --- a/docs/rp2/quickref.rst +++ b/docs/rp2/quickref.rst @@ -92,6 +92,37 @@ Use the :ref:`machine.Pin ` class:: p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation +Programmable IO (PIO) +--------------------- + +PIO is useful to build low-level IO interfaces from scratch. See the :mod:`rp2` module +for detailed explaination of the assembly instructions. + +Example using PIO to blink an LED at 1Hz:: + + from machine import Pin + import rp2 + + @rp2.asm_pio(set_init=rp2.PIO.OUT_LOW) + def blink_1hz(): + # Cycles: 1 + 7 + 32 * (30 + 1) = 1000 + set(pins, 1) + set(x, 31) [6] + label("delay_high") + nop() [29] + jmp(x_dec, "delay_high") + + # Cycles: 1 + 7 + 32 * (30 + 1) = 1000 + set(pins, 0) + set(x, 31) [6] + label("delay_low") + nop() [29] + jmp(x_dec, "delay_low") + + # Create and start a StateMachine with blink_1hz, outputting on Pin(25) + sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25)) + sm.active(1) + UART (serial bus) ----------------- @@ -219,6 +250,26 @@ has the same methods as software I2C above:: i2c = I2C(0) # default assignment: scl=Pin(9), sda=Pin(8) i2c = I2C(1, scl=Pin(3), sda=Pin(2), freq=400_000) +I2S bus +------- + +See :ref:`machine.I2S `. :: + + from machine import I2S, Pin + + i2s = I2S(0, sck=Pin(16), ws=Pin(17), sd=Pin(18), mode=I2S.TX, bits=16, format=I2S.STEREO, rate=44100, ibuf=40000) # create I2S object + i2s.write(buf) # write buffer of audio samples to I2S device + + i2s = I2S(1, sck=Pin(0), ws=Pin(1), sd=Pin(2), mode=I2S.RX, bits=16, format=I2S.MONO, rate=22050, ibuf=40000) # create I2S object + i2s.readinto(buf) # fill buffer with audio samples from I2S device + +The ``ws`` pin number must be one greater than the ``sck`` pin number. + +The I2S class is currently available as a Technical Preview. During the preview period, feedback from +users is encouraged. Based on this feedback, the I2S class API and implementation may be changed. + +Two I2S buses are supported with id=0 and id=1. + Real time clock (RTC) --------------------- diff --git a/docs/rp2/tutorial/intro.rst b/docs/rp2/tutorial/intro.rst index 5609ab379..69c3e6b0a 100644 --- a/docs/rp2/tutorial/intro.rst +++ b/docs/rp2/tutorial/intro.rst @@ -4,3 +4,8 @@ Getting started with MicroPython on the RP2xxx ============================================== Let's get started! + +.. toctree:: + :maxdepth: 1 + + pio.rst diff --git a/docs/rp2/tutorial/pio.rst b/docs/rp2/tutorial/pio.rst new file mode 100644 index 000000000..9981aed83 --- /dev/null +++ b/docs/rp2/tutorial/pio.rst @@ -0,0 +1,123 @@ +Programmable IO +=============== + +The RP2040 has hardware support for standard communication protocols like I2C, +SPI and UART. For protocols where there is no hardware support, or where there +is a requirement of custom I/O behaviour, Programmable Input Output (PIO) comes +into play. Also, some MicroPython applications make use of a technique called +bit banging in which pins are rapidly turned on and off to transmit data. This +can make the entire process slow as the processor concentrates on bit banging +rather than executing other logic. However, PIO allows bit banging to happen +in the background while the CPU is executing the main work. + +Along with the two central Cortex-M0+ processing cores, the RP2040 has two PIO +blocks each of which has four independent state machines. These state machines +can transfer data to/from other entities using First-In-First-Out (FIFO) buffers, +which allow the state machine and main processor to work independently yet also +synchronise their data. Each FIFO has four words (each of 32 bits) which can be +linked to the DMA to transfer larger amounts of data. + +All PIO instructions follow a common pattern:: + + .side() [] + +The side-set ``.side(...)`` and delay ``[...]`` parts are both optional, and if +specified allow the instruction to perform more than one operation. This keeps +PIO programs small and efficient. + +There are nine instructions which perform the following tasks: + +- ``jmp()`` transfers control to a different part of the code +- ``wait()`` pauses until a particular action happens +- ``in_()`` shifts the bits from a source (scratch register or set of pins) to the + input shift register +- ``out()`` shifts the bits from the output shift register to a destination +- ``push()`` sends data to the RX FIFO +- ``pull()`` receives data from the TX FIFO +- ``mov()`` moves data from a source to a destination +- ``irq()`` sets or clears an IRQ flag +- ``set()`` writes a literal value to a destination + +The instruction modifiers are: + +- ``.side()`` sets the side-set pins at the start of the instruction +- ``[]`` delays for a certain number of cycles after execution of the instruction + +There are also directives: + +- ``wrap_target()`` specifies where the program execution will get continued from +- ``wrap()`` specifies the instruction where the control flow of the program will + get wrapped from +- ``label()`` sets a label for use with ``jmp()`` instructions +- ``word()`` emits a raw 16-bit value which acts as an instruction in the program + +An example +---------- + +Take the ``pio_1hz.py`` example for a simple understanding of how to use the PIO +and state machines. Below is the code for reference. + +.. code-block:: python3 + + # Example using PIO to blink an LED and raise an IRQ at 1Hz. + + import time + from machine import Pin + import rp2 + + + @rp2.asm_pio(set_init=rp2.PIO.OUT_LOW) + def blink_1hz(): + # Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000 + irq(rel(0)) + set(pins, 1) + set(x, 31) [5] + label("delay_high") + nop() [29] + jmp(x_dec, "delay_high") + + # Cycles: 1 + 7 + 32 * (30 + 1) = 1000 + set(pins, 0) + set(x, 31) [6] + label("delay_low") + nop() [29] + jmp(x_dec, "delay_low") + + + # Create the StateMachine with the blink_1hz program, outputting on Pin(25). + sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25)) + + # Set the IRQ handler to print the millisecond timestamp. + sm.irq(lambda p: print(time.ticks_ms())) + + # Start the StateMachine. + sm.active(1) + +This creates an instance of class :class:`rp2.StateMachine` which runs the +``blink_1hz`` program at 2000Hz, and connects to pin 25. The ``blink_1hz`` +program uses the PIO to blink an LED connected to this pin at 1Hz, and also +raises an IRQ as the LED turns on. This IRQ then calls the ``lambda`` function +which prints out a millisecond timestamp. + +The ``blink_1hz`` program is a PIO assembler routine. It connects to a single +pin which is configured as an output and starts out low. The instructions do +the following: + +- ``irq(rel(0))`` raises the IRQ associated with the state machine. +- The LED is turned on via the ``set(pins, 1)`` instruction. +- The value 31 is put into register X, and then there is a delay for 5 more + cycles, specified by the ``[5]``. +- The ``nop() [29]`` instruction waits for 30 cycles. +- The ``jmp(x_dec, "delay_high")`` will keep looping to the ``delay_high`` label + as long as the register X is non-zero, and will also post-decrement X. Since + X starts with the value 31 this jump will happen 31 times, so the ``nop() [29]`` + runs 32 times in total (note there is also one instruction cycle taken by the + ``jmp`` for each of these 32 loops). +- ``set(pins, 0)`` will turn the LED off by setting pin 25 low. +- Another 32 loops of ``nop() [29]`` and ``jmp(...)`` will execute. +- Because ``wrap_target()`` and ``wrap()`` are not specified, their default will + be used and execution of the program will wrap around from the bottom to the + top. This wrapping does not cost any execution cycles. + +The entire routine takes exactly 2000 cycles of the state machine. Setting the +frequency of the state machine to 2000Hz makes the LED blink at 1Hz. diff --git a/docs/wipy/quickref.rst b/docs/wipy/quickref.rst index f9ea3d501..4c3b969bd 100644 --- a/docs/wipy/quickref.rst +++ b/docs/wipy/quickref.rst @@ -154,7 +154,7 @@ See :ref:`machine.RTC ` :: pass # do some non blocking operations # warning printing on an irq via telnet is not - # possible, only via UART + # possible, only via UART # create a RTC alarm that expires after 5 seconds rtc.alarm(time=5000, repeat=False) @@ -179,7 +179,7 @@ See :ref:`machine.SD `. :: sd = SD() os.mount(sd, '/sd') -WLAN (WiFi) +WLAN (WiFi) ----------- See :ref:`network.WLAN ` and :mod:`machine`. :: diff --git a/docs/wipy/tutorial/reset.rst b/docs/wipy/tutorial/reset.rst index ece28498b..1715d3e29 100644 --- a/docs/wipy/tutorial/reset.rst +++ b/docs/wipy/tutorial/reset.rst @@ -1,10 +1,10 @@ Reset and boot modes ==================== -There are soft resets and hard resets. +There are soft resets and hard resets. - - A soft reset simply clears the state of the MicroPython virtual machine, - but leaves hardware peripherals unaffected. To do a soft reset, simply press + - A soft reset simply clears the state of the MicroPython virtual machine, + but leaves hardware peripherals unaffected. To do a soft reset, simply press **Ctrl+D** on the REPL, or within a script do:: import sys diff --git a/docs/wipy/tutorial/timer.rst b/docs/wipy/tutorial/timer.rst index c87ac4495..7cd7d0f13 100644 --- a/docs/wipy/tutorial/timer.rst +++ b/docs/wipy/tutorial/timer.rst @@ -5,7 +5,7 @@ Timers can be used for a great variety of tasks, calling a function periodically counting events, and generating a PWM signal are among the most common use cases. Each timer consists of two 16-bit channels and this channels can be tied together to form one 32-bit timer. The operating mode needs to be configured per timer, but then -the period (or the frequency) can be independently configured on each channel. +the period (or the frequency) can be independently configured on each channel. By using the callback method, the timer event can call a Python function. Example usage to toggle an LED at a fixed frequency:: diff --git a/docs/wipy/tutorial/wlan.rst b/docs/wipy/tutorial/wlan.rst index 434367cd9..bdfd3e0a5 100644 --- a/docs/wipy/tutorial/wlan.rst +++ b/docs/wipy/tutorial/wlan.rst @@ -13,9 +13,9 @@ You can check the current mode (which is always ``WLAN.AP`` after power up):: >>> wlan.mode() -.. warning:: - When you change the WLAN mode following the instructions below, your WLAN - connection to the WiPy will be broken. This means you will not be able +.. warning:: + When you change the WLAN mode following the instructions below, your WLAN + connection to the WiPy will be broken. This means you will not be able to run these commands interactively over the WLAN. There are two ways around this:: diff --git a/docs/zephyr/tutorial/repl.rst b/docs/zephyr/tutorial/repl.rst index a7e8955d0..71e732e61 100644 --- a/docs/zephyr/tutorial/repl.rst +++ b/docs/zephyr/tutorial/repl.rst @@ -31,8 +31,8 @@ With your serial program open (PuTTY, screen, picocom, etc) you may see a blank screen with a flashing cursor. Press Enter (or reset the board) and you should be presented with the following text:: - *** Booting Zephyr OS build v2.6.0-rc1-416-g3056c5ec30ad *** - MicroPython v2.6.0-rc1-416-g3056c5ec30 on 2021-06-24; zephyr-frdm_k64f with mk64f12 + *** Booting Zephyr OS build zephyr-v2.7.0 *** + MicroPython v1.17-288-gb695f5a70-dirty on 2022-01-03; zephyr-frdm_k64f with mk64f12 Type "help()" for more information. >>> diff --git a/drivers/dht/dht.py b/drivers/dht/dht.py index 1163b382b..9be23b3ae 100644 --- a/drivers/dht/dht.py +++ b/drivers/dht/dht.py @@ -1,9 +1,15 @@ # DHT11/DHT22 driver for MicroPython on ESP8266 # MIT license; Copyright (c) 2016 Damien P. George -try: +import sys + +if sys.platform.startswith("esp"): from esp import dht_readinto -except: +elif sys.platform == "mimxrt": + from mimxrt import dht_readinto +elif sys.platform == "rp2": + from rp2 import dht_readinto +else: from pyb import dht_readinto diff --git a/drivers/lsm6dsox/lsm6dsox.py b/drivers/lsm6dsox/lsm6dsox.py new file mode 100644 index 000000000..56a3abcbe --- /dev/null +++ b/drivers/lsm6dsox/lsm6dsox.py @@ -0,0 +1,234 @@ +""" +LSM6DSOX STMicro driver for MicroPython based on LSM9DS1: +Source repo: https://github.com/hoihu/projects/tree/master/raspi-hat + +The MIT License (MIT) + +Copyright (c) 2021 Damien P. George +Copyright (c) 2021 Ibrahim Abdelkader + +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. + +Basic example usage: + +import time +from lsm6dsox import LSM6DSOX + +from machine import Pin, I2C +lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12))) + +while (True): + print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_accel())) + print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_gyro())) + print("") + time.sleep_ms(100) +""" +import array +from micropython import const + + +class LSM6DSOX: + _CTRL3_C = const(0x12) + _CTRL1_XL = const(0x10) + _CTRL8_XL = const(0x17) + _CTRL9_XL = const(0x18) + + _CTRL2_G = const(0x11) + _CTRL7_G = const(0x16) + + _OUTX_L_G = const(0x22) + _OUTX_L_XL = const(0x28) + _MLC_STATUS = const(0x38) + + _DEFAULT_ADDR = const(0x6A) + _WHO_AM_I_REG = const(0x0F) + + _FUNC_CFG_ACCESS = const(0x01) + _FUNC_CFG_BANK_USER = const(0) + _FUNC_CFG_BANK_HUB = const(1) + _FUNC_CFG_BANK_EMBED = const(2) + + _MLC0_SRC = const(0x70) + _MLC_INT1 = const(0x0D) + _TAP_CFG0 = const(0x56) + + _EMB_FUNC_EN_A = const(0x04) + _EMB_FUNC_EN_B = const(0x05) + + def __init__( + self, + i2c, + address=_DEFAULT_ADDR, + gyro_odr=104, + accel_odr=104, + gyro_scale=2000, + accel_scale=4, + ucf=None, + ): + """Initalizes Gyro and Accelerator. + accel_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz) + gyro_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz) + gyro_scale: (245dps, 500dps, 1000dps, 2000dps) + accel_scale: (+/-2g, +/-4g, +/-8g, +-16g) + ucf: MLC program to load. + """ + self.i2c = i2c + self.address = address + + # check the id of the Accelerometer/Gyro + if self.__read_reg(_WHO_AM_I_REG) != 108: + raise OSError("No LSM6DS device was found at address 0x%x" % (self.address)) + + # allocate scratch buffer for efficient conversions and memread op's + self.scratch_int = array.array("h", [0, 0, 0]) + + SCALE_GYRO = {250: 0, 500: 1, 1000: 2, 2000: 3} + SCALE_ACCEL = {2: 0, 4: 2, 8: 3, 16: 1} + # XL_HM_MODE = 0 by default. G_HM_MODE = 0 by default. + ODR = { + 0: 0x00, + 1.6: 0x08, + 3.33: 0x09, + 6.66: 0x0A, + 12.5: 0x01, + 26: 0x02, + 52: 0x03, + 104: 0x04, + 208: 0x05, + 416: 0x06, + 888: 0x07, + } + + gyro_odr = round(gyro_odr, 2) + accel_odr = round(accel_odr, 2) + + # Sanity checks + if not gyro_odr in ODR: + raise ValueError("Invalid sampling rate: %d" % accel_odr) + if not gyro_scale in SCALE_GYRO: + raise ValueError("invalid gyro scaling: %d" % gyro_scale) + if not accel_odr in ODR: + raise ValueError("Invalid sampling rate: %d" % accel_odr) + if not accel_scale in SCALE_ACCEL: + raise ValueError("invalid accelerometer scaling: %d" % accel_scale) + + # Soft-reset the device. + self.reset() + + # Load and configure MLC if UCF file is provided + if ucf != None: + self.load_mlc(ucf) + + # Set Gyroscope datarate and scale. + # Note output from LPF2 second filtering stage is selected. See Figure 18. + self.__write_reg(_CTRL1_XL, (ODR[accel_odr] << 4) | (SCALE_ACCEL[accel_scale] << 2) | 2) + + # Enable LPF2 and HPF fast-settling mode, ODR/4 + self.__write_reg(_CTRL8_XL, 0x09) + + # Set Gyroscope datarate and scale. + self.__write_reg(_CTRL2_G, (ODR[gyro_odr] << 4) | (SCALE_GYRO[gyro_scale] << 2) | 0) + + self.gyro_scale = 32768 / gyro_scale + self.accel_scale = 32768 / accel_scale + + def __read_reg(self, reg, size=1): + buf = self.i2c.readfrom_mem(self.address, reg, size) + if size == 1: + return int(buf[0]) + return [int(x) for x in buf] + + def __write_reg(self, reg, val): + self.i2c.writeto_mem(self.address, reg, bytes([val])) + + def reset(self): + self.__write_reg(_CTRL3_C, self.__read_reg(_CTRL3_C) | 0x1) + for i in range(0, 10): + if (self.__read_reg(_CTRL3_C) & 0x01) == 0: + return + time.sleep_ms(10) + raise OSError("Failed to reset LSM6DS device.") + + def set_mem_bank(self, bank): + cfg = self.__read_reg(_FUNC_CFG_ACCESS) & 0x3F + self.__write_reg(_FUNC_CFG_ACCESS, cfg | (bank << 6)) + + def set_embedded_functions(self, enable, emb_ab=None): + self.set_mem_bank(_FUNC_CFG_BANK_EMBED) + if enable: + self.__write_reg(_EMB_FUNC_EN_A, emb_ab[0]) + self.__write_reg(_EMB_FUNC_EN_B, emb_ab[1]) + else: + emb_a = self.__read_reg(_EMB_FUNC_EN_A) + emb_b = self.__read_reg(_EMB_FUNC_EN_B) + self.__write_reg(_EMB_FUNC_EN_A, (emb_a & 0xC7)) + self.__write_reg(_EMB_FUNC_EN_B, (emb_b & 0xE6)) + emb_ab = (emb_a, emb_b) + + self.set_mem_bank(_FUNC_CFG_BANK_USER) + return emb_ab + + def load_mlc(self, ucf): + # Load MLC config from file + with open(ucf, "r") as ucf_file: + for l in ucf_file: + if l.startswith("Ac"): + v = [int(v, 16) for v in l.strip().split(" ")[1:3]] + self.__write_reg(v[0], v[1]) + + emb_ab = self.set_embedded_functions(False) + + # Disable I3C interface + self.__write_reg(_CTRL9_XL, self.__read_reg(_CTRL9_XL) | 0x01) + + # Enable Block Data Update + self.__write_reg(_CTRL3_C, self.__read_reg(_CTRL3_C) | 0x40) + + # Route signals on interrupt pin 1 + self.set_mem_bank(_FUNC_CFG_BANK_EMBED) + self.__write_reg(_MLC_INT1, self.__read_reg(_MLC_INT1) & 0x01) + self.set_mem_bank(_FUNC_CFG_BANK_USER) + + # Configure interrupt pin mode + self.__write_reg(_TAP_CFG0, self.__read_reg(_TAP_CFG0) | 0x41) + + self.set_embedded_functions(True, emb_ab) + + def read_mlc_output(self): + buf = None + if self.__read_reg(_MLC_STATUS) & 0x1: + self.__read_reg(0x1A, size=12) + self.set_mem_bank(_FUNC_CFG_BANK_EMBED) + buf = self.__read_reg(_MLC0_SRC, 8) + self.set_mem_bank(_FUNC_CFG_BANK_USER) + return buf + + def read_gyro(self): + """Returns gyroscope vector in degrees/sec.""" + mv = memoryview(self.scratch_int) + f = self.gyro_scale + self.i2c.readfrom_mem_into(self.address, _OUTX_L_G, mv) + return (mv[0] / f, mv[1] / f, mv[2] / f) + + def read_accel(self): + """Returns acceleration vector in gravity units (9.81m/s^2).""" + mv = memoryview(self.scratch_int) + f = self.accel_scale + self.i2c.readfrom_mem_into(self.address, _OUTX_L_XL, mv) + return (mv[0] / f, mv[1] / f, mv[2] / f) diff --git a/drivers/lsm6dsox/lsm6dsox_basic.py b/drivers/lsm6dsox/lsm6dsox_basic.py new file mode 100644 index 000000000..6c747ae55 --- /dev/null +++ b/drivers/lsm6dsox/lsm6dsox_basic.py @@ -0,0 +1,13 @@ +# LSM6DSOX Basic Example. +import time +from lsm6dsox import LSM6DSOX + +from machine import Pin, I2C + +lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12))) + +while True: + print("Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.read_accel())) + print("Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.read_gyro())) + print("") + time.sleep_ms(100) diff --git a/drivers/lsm6dsox/lsm6dsox_mlc.py b/drivers/lsm6dsox/lsm6dsox_mlc.py new file mode 100644 index 000000000..866498d0c --- /dev/null +++ b/drivers/lsm6dsox/lsm6dsox_mlc.py @@ -0,0 +1,48 @@ +# LSM6DSOX IMU MLC (Machine Learning Core) Example. +# Download the raw UCF file, copy to storage and reset. + +# NOTE: The pre-trained models (UCF files) for the examples can be found here: +# https://github.com/STMicroelectronics/STMems_Machine_Learning_Core/tree/master/application_examples/lsm6dsox + +import time +from lsm6dsox import LSM6DSOX +from machine import Pin, I2C + +INT_MODE = True # Run in interrupt mode. +INT_FLAG = False # Set True on interrupt. + + +def imu_int_handler(pin): + global INT_FLAG + INT_FLAG = True + + +if INT_MODE == True: + int_pin = Pin(24) + int_pin.irq(handler=imu_int_handler, trigger=Pin.IRQ_RISING) + +i2c = I2C(0, scl=Pin(13), sda=Pin(12)) + +# Vibration detection example +UCF_FILE = "lsm6dsox_vibration_monitoring.ucf" +UCF_LABELS = {0: "no vibration", 1: "low vibration", 2: "high vibration"} +# NOTE: Selected data rate and scale must match the MLC data rate and scale. +lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=2000, accel_scale=4, ucf=UCF_FILE) + +# Head gestures example +# UCF_FILE = "lsm6dsox_head_gestures.ucf" +# UCF_LABELS = {0:"Nod", 1:"Shake", 2:"Stationary", 3:"Swing", 4:"Walk"} +# NOTE: Selected data rate and scale must match the MLC data rate and scale. +# lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=250, accel_scale=2, ucf=UCF_FILE) + +print("MLC configured...") + +while True: + if INT_MODE: + if INT_FLAG: + INT_FLAG = False + print(UCF_LABELS[lsm.read_mlc_output()[0]]) + else: + buf = lsm.read_mlc_output() + if buf != None: + print(UCF_LABELS[buf[0]]) diff --git a/drivers/neopixel/neopixel.py b/drivers/neopixel/neopixel.py index 0032d3618..caa12dc84 100644 --- a/drivers/neopixel/neopixel.py +++ b/drivers/neopixel/neopixel.py @@ -36,10 +36,14 @@ class NeoPixel: def fill(self, v): b = self.buf - for i in range(self.bpp): + l = len(self.buf) + bpp = self.bpp + for i in range(bpp): c = v[i] - for j in range(self.ORDER[i], len(self.buf), self.bpp): + j = self.ORDER[i] + while j < l: b[j] = c + j += bpp def write(self): # BITSTREAM_TYPE_HIGH_LOW = 0 diff --git a/drivers/ninaw10/nina_bsp.h b/drivers/ninaw10/nina_bsp.h new file mode 100644 index 000000000..362583843 --- /dev/null +++ b/drivers/ninaw10/nina_bsp.h @@ -0,0 +1,39 @@ +/* + * This file is part of the OpenMV project, https://openmv.io. + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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. + * + * NINA-W10 driver BSP. + */ +#ifndef MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H +#define MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H + +int nina_bsp_init(void); +int nina_bsp_deinit(void); +int nina_bsp_read_irq(void); +int nina_bsp_spi_slave_select(uint32_t timeout); +int nina_bsp_spi_slave_deselect(void); +int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size); + +#endif // MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H diff --git a/drivers/ninaw10/nina_bt_hci.c b/drivers/ninaw10/nina_bt_hci.c new file mode 100644 index 000000000..6dc320447 --- /dev/null +++ b/drivers/ninaw10/nina_bt_hci.c @@ -0,0 +1,150 @@ +/* + * This file is part of the OpenMV project, https://openmv.io. + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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. + * + * NINA-W10 Bluetooth HCI driver. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10 + +#include +#include + +#include "py/runtime.h" +#include "extmod/mpbthci.h" + +#define HCI_COMMAND_PACKET (0x01) +#define HCI_ACLDATA_PACKET (0x02) +#define HCI_EVENT_PACKET (0x04) + +#define HCI_COMMAND_COMPLETE (0x0e) +#define HCI_COMMAND_TIMEOUT (3000) + +#define OGF_LINK_CTL (0x01) +#define OGF_HOST_CTL (0x03) + +#define OCF_SET_EVENT_MASK (0x0001) +#define OCF_RESET (0x0003) + +#define error_printf(...) mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__) +#define debug_printf(...) // mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__) + +// Provided by the port, and also possibly shared with the stack. +extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; + +static int nina_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) { + uint8_t *buf = mp_bluetooth_hci_cmd_buf; + + buf[0] = HCI_COMMAND_PACKET; + buf[1] = ocf; + buf[2] = ogf << 2 | ocf >> 8; + buf[3] = param_len; + + if (param_len) { + memcpy(buf + 4, param_buf, param_len); + } + + debug_printf("HCI Command: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]); + + mp_bluetooth_hci_uart_write(buf, 4 + param_len); + + // Receive HCI event packet, initially reading 3 bytes (HCI Event, Event code, Plen). + for (mp_uint_t start = mp_hal_ticks_ms(), size = 3, i = 0; i < size;) { + while (!mp_bluetooth_hci_uart_any()) { + MICROPY_EVENT_POLL_HOOK + // Timeout. + if ((mp_hal_ticks_ms() - start) > HCI_COMMAND_TIMEOUT) { + error_printf("timeout waiting for HCI packet\n"); + return -1; + } + } + + buf[i] = mp_bluetooth_hci_uart_readchar(); + + // There seems to be a sync issue with this fw/module. + if (i == 0 && buf[0] == 0xFF) { + continue; + } + + // Check for packet type. + if (i == 0 && buf[0] != HCI_EVENT_PACKET) { + error_printf("unexpected HCI packet: %02x\n", buf[0]); + return -1; + } + + // Sanity check the packet parameters length. + if (i == 2 && ((size += buf[2]) > sizeof(mp_bluetooth_hci_cmd_buf))) { + error_printf("unexpected event packet length: %d\n", size); + return -1; + } + + i++; + } + + // We're only looking for command complete events. + if (buf[1] != HCI_COMMAND_COMPLETE || buf[4] != ocf || buf[5] != (ogf << 2 | ocf >> 8)) { + error_printf("response mismatch: %02x %02x\n", buf[4], buf[5]); + return -1; + } + + // Log event. + debug_printf("HCI Event packet: %02x %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + + // Status code. + return buf[6]; +} + +int mp_bluetooth_hci_controller_init(void) { + // This is called immediately after the UART is initialised during stack initialisation. + mp_hal_pin_output(MICROPY_HW_NINA_GPIO1); + mp_hal_pin_output(MICROPY_HW_NINA_RESET); + + mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0); + mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0); + mp_hal_delay_ms(100); + + mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1); + mp_hal_delay_ms(750); + + // The UART must be re-initialize here because the GPIO1/RX pin is used initially + // to reset the module in Bluetooth mode. This will change back the pin to UART RX. + mp_bluetooth_hci_uart_init(0, 0); + + // Send reset command + return nina_hci_cmd(OGF_HOST_CTL, OCF_RESET, 0, NULL); + // It seems that nothing else is needed for now. +} + +int mp_bluetooth_hci_controller_deinit(void) { + // Reset module + mp_hal_pin_output(MICROPY_HW_NINA_RESET); + mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0); + return 0; +} + +#endif diff --git a/drivers/ninaw10/nina_wifi_bsp.c b/drivers/ninaw10/nina_wifi_bsp.c new file mode 100644 index 000000000..c5a9b9b10 --- /dev/null +++ b/drivers/ninaw10/nina_wifi_bsp.c @@ -0,0 +1,139 @@ +/* + * This file is part of the OpenMV project, https://openmv.io. + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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. + * + * NINA-W10 driver BSP implementation. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_NETWORK_NINAW10 + +#include +#include + +#include "py/runtime.h" +#include "modmachine.h" +#include "extmod/machine_spi.h" +#include "mpconfigboard.h" + +#include "nina_bsp.h" +#include "nina_wifi_drv.h" + +#if NINA_DEBUG +#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#else +#define debug_printf(...) +#endif + +int nina_bsp_init(void) { + mp_hal_pin_output(MICROPY_HW_NINA_GPIO1); + mp_hal_pin_input(MICROPY_HW_NINA_ACK); + mp_hal_pin_output(MICROPY_HW_NINA_RESET); + mp_hal_pin_output(MICROPY_HW_NINA_GPIO0); + + // Reset module in WiFi mode + mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1); + mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1); + + mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0); + mp_hal_delay_ms(100); + + mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1); + mp_hal_delay_ms(750); + + mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 0); + mp_hal_pin_input(MICROPY_HW_NINA_GPIO0); + + // Initialize SPI. + mp_obj_t args[] = { + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_ID), + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_BAUDRATE), + }; + + MP_STATE_PORT(mp_wifi_spi) = machine_spi_type.make_new((mp_obj_t)&machine_spi_type, 2, 0, args); + return 0; +} + +int nina_bsp_deinit(void) { + mp_hal_pin_output(MICROPY_HW_NINA_GPIO1); + mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1); + + mp_hal_pin_output(MICROPY_HW_NINA_RESET); + mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0); + mp_hal_delay_ms(100); + + mp_hal_pin_output(MICROPY_HW_NINA_GPIO0); + mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1); + return 0; +} + +int nina_bsp_read_irq(void) { + return mp_hal_pin_read(MICROPY_HW_NINA_GPIO0); +} + +int nina_bsp_spi_slave_select(uint32_t timeout) { + // Wait for ACK to go low. + for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 1; mp_hal_delay_ms(1)) { + if ((mp_hal_ticks_ms() - start) >= timeout) { + return -1; + } + } + + // Chip select. + mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0); + + // Wait for ACK to go high. + for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 0; mp_hal_delay_ms(1)) { + if ((mp_hal_ticks_ms() - start) >= 100) { + mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1); + return -1; + } + } + + return 0; +} + +int nina_bsp_spi_slave_deselect(void) { + mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1); + return 0; +} + +int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) { + mp_obj_t mp_wifi_spi = MP_STATE_PORT(mp_wifi_spi); + ((mp_machine_spi_p_t *)machine_spi_type.protocol)->transfer(mp_wifi_spi, size, tx_buf, rx_buf); + #if NINA_DEBUG + for (int i = 0; i < size; i++) { + if (tx_buf) { + debug_printf("0x%x ", tx_buf[i]); + } else { + debug_printf("0x%x ", rx_buf[i]); + } + } + #endif + return 0; +} + +#endif // MICROPY_PY_NETWORK_NINAW10 diff --git a/drivers/ninaw10/nina_wifi_drv.c b/drivers/ninaw10/nina_wifi_drv.c new file mode 100644 index 000000000..b7c016f42 --- /dev/null +++ b/drivers/ninaw10/nina_wifi_drv.c @@ -0,0 +1,931 @@ +/* + * This file is part of the OpenMV project, https://openmv.io. + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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. + * + * NINA-W10 WiFi driver. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_NETWORK_NINAW10 + +#include +#include +#include + +#include "nina_bsp.h" +#include "nina_wifi_drv.h" + +#define SPI_ACK (1) +#define SPI_ERR (0xFF) + +#define NO_SOCKET_AVAIL (255) + +#define CMD_START (0xE0) +#define CMD_END (0xEE) +#define CMD_ERROR (0xEF) +#define CMD_REPLY (1 << 7) + +#define ARG_8BITS (1) +#define ARG_16BITS (2) + +#define ARG_STR(x) {strlen(x), (const void *)x} +#define ARG_BYTE(x) {1, (uint8_t [1]) {x}} +#define ARG_SHORT(x) {2, (uint16_t [1]) {x}} +#define ARG_WORD(x) {4, (uint32_t [1]) {x}} + +#define NINA_ARGS(...) (nina_args_t []) {__VA_ARGS__} +#define NINA_VALS(...) (nina_vals_t []) {__VA_ARGS__} + +#define NINA_SSELECT_TIMEOUT (10000) +#define NINA_RESPONSE_TIMEOUT (1000) +#define NINA_CONNECT_TIMEOUT (10000) + +#if NINA_DEBUG +#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#else +#define debug_printf(...) +#endif + +#ifndef __REVSH +#define __REVSH(x) ((((uint16_t)x) << 8) | (((uint16_t)x) >> 8)) +#endif + +typedef struct { + uint16_t size; + const void *data; +} nina_args_t; + +typedef struct { + uint16_t *size; + void *data; +} nina_vals_t; + +typedef enum { + // STA mode commands. + NINA_CMD_CONNECT_OPEN = 0x10, + NINA_CMD_CONNECT_WEP = 0x11, + NINA_CMD_CONNECT_WPA = 0x12, + NINA_CMD_GET_SSID = 0x23, + NINA_CMD_GET_BSSID = 0x24, + NINA_CMD_GET_RSSI = 0x25, + NINA_CMD_GET_ENCRYPT = 0x26, + + // AP mode commands. + NINA_CMD_START_AP_OPEN = 0x18, + NINA_CMD_START_AP_WEP = 0x19, + + // AP mode scan commands. + NINA_CMD_AP_START_SCAN = 0x36, + NINA_CMD_AP_SCAN_RESULT = 0x27, + NINA_CMD_AP_GET_RSSI = 0x32, + NINA_CMD_AP_GET_ENCRYPT = 0x33, + NINA_CMD_AP_GET_BSSID = 0x3C, + NINA_CMD_AP_GET_CHANNEL = 0x3D, + + // Disonnect/status commands. + NINA_CMD_DISCONNECT = 0x30, + NINA_CMD_CONN_STATUS = 0x20, + + // Interface config commands. + NINA_CMD_SET_IF_CONFIG = 0x14, + NINA_CMD_GET_IF_CONFIG = 0x21, + NINA_CMD_SET_DNS_CONFIG = 0x15, + + // Hostname/Resolv commands. + NINA_CMD_SET_HOSTNAME = 0x16, + NINA_CMD_HOST_BY_NAME = 0x34, + NINA_CMD_GET_HOST_BY_NAME = 0x35, + + // Misc commands. + NINA_CMD_SET_POWER = 0x17, + NINA_CMD_PING = 0x3E, + NINA_CMD_GET_TIME = 0x3B, + NINA_CMD_GET_FW_VERSION = 0x37, + NINA_CMD_DEBUG_MODE = 0x1A, + NINA_CMD_TEMP_SENSOR = 0x1B, + NINA_CMD_GET_MAC_ADDR = 0x22, + + // Sockets commands. + NINA_CMD_SOCKET_OPEN = 0x3F, + NINA_CMD_SOCKET_CLOSE = 0x2E, + NINA_CMD_SOCKET_CONNECT = 0x2D, + NINA_CMD_SOCKET_ACCEPT = 0x2B, + NINA_CMD_SOCKET_BIND = 0x28, + NINA_CMD_SOCKET_STATE = 0x2F, + NINA_CMD_SOCKET_REMOTE_ADDR = 0x3A, + + // TCP commands + NINA_CMD_TCP_SEND = 0x44, + NINA_CMD_TCP_RECV = 0x45, + NINA_CMD_TCP_ACK = 0x2A, + + // UDP commands. + NINA_CMD_UDP_SEND = 0x46, + NINA_CMD_UDP_RECV = 0x45, + NINA_CMD_UDP_ACK = 0x39, + + // Pin control commands. + NINA_CMD_SET_PIN_MODE = 0x50, + NINA_CMD_SET_DIGITAL_WRITE = 0x51, + NINA_CMD_GET_DIGITAL_READ = 0x53, + NINA_CMD_SET_ANALOG_WRITE = 0x52, + NINA_CMD_GET_ANALOG_READ = 0x54, + + // File send/recv commands. + NINA_CMD_CMD_WRITE_FILE = 0x60, + NINA_CMD_CMD_READ_FILE = 0x61, + NINA_CMD_CMD_DELETE_FILE = 0x62, + NINA_CMD_CMD_EXISTS_FILE = 0x63, + NINA_CMD_CMD_DOWNLOAD_FILE = 0x64, + + // OTA upgrade commands. + NINA_CMD_CMD_APPLY_OTA = 0x65, + NINA_CMD_CMD_RENAME_FILE = 0x66, + NINA_CMD_CMD_DOWNLOAD_OTA = 0x67, +} nina_cmd_t; + +typedef enum { + NINA_STATUS_IDLE = 0, + NINA_STATUS_NO_SSID_AVAIL, + NINA_STATUS_SCAN_COMPLETED, + NINA_STATUS_CONNECTED, + NINA_STATUS_CONNECT_FAILED, + NINA_STATUS_CONNECTION_LOST, + NINA_STATUS_DISCONNECTED, + NINA_STATUS_AP_LISTENING, + NINA_STATUS_AP_CONNECTED, + NINA_STATUS_AP_FAILED +} nina_status_t; + +typedef enum { + SOCKET_STATE_CLOSED = 0, + SOCKET_STATE_LISTEN, + SOCKET_STATE_SYN_SENT, + SOCKET_STATE_SYN_RCVD, + SOCKET_STATE_ESTABLISHED, + SOCKET_STATE_FIN_WAIT_1, + SOCKET_STATE_FIN_WAIT_2, + SOCKET_STATE_CLOSE_WAIT, + SOCKET_STATE_CLOSING, + SOCKET_STATE_LAST_ACK, + SOCKET_STATE_TIME_WAIT +} nina_sock_state_t; + +static uint8_t nina_bsp_spi_read_byte(void) { + uint8_t byte = 0; + nina_bsp_spi_transfer(NULL, &byte, 1); + return byte; +} + +static int nina_wait_for_cmd(uint8_t cmd, uint32_t timeout) { + uint8_t buf = 0; + for (mp_uint_t start = mp_hal_ticks_ms(); ;) { + buf = nina_bsp_spi_read_byte(); + if (buf == CMD_ERROR || buf == cmd + || ((mp_hal_ticks_ms() - start) >= timeout)) { + break; + } + mp_hal_delay_ms(1); + } + + return (buf == cmd) ? 0 : -1; +} + +static int nina_send_command(uint32_t cmd, uint32_t nargs, uint32_t width, nina_args_t *args) { + int ret = -1; + uint32_t length = 4; // 3 bytes header + 1 end byte + + debug_printf("nina_send_command (cmd 0x%x nargs %d width %d): ", cmd, nargs, width); + + if (nina_bsp_spi_slave_select(NINA_SSELECT_TIMEOUT) != 0) { + return -1; + } + + // Send command header. + uint8_t cmdbuf_hdr[3] = {CMD_START, cmd, nargs}; + if (nina_bsp_spi_transfer(cmdbuf_hdr, NULL, sizeof(cmdbuf_hdr)) != 0) { + goto error_out; + } + + // Send command arg(s). + for (uint32_t i = 0; i < nargs; i++) { + // Send size MSB first if 2 bytes. + uint16_t size = (width == ARG_8BITS) ? args[i].size : __REVSH(args[i].size); + + // Send arg length. + if (nina_bsp_spi_transfer((uint8_t *)&size, NULL, width) != 0) { + goto error_out; + } + + // Send arg value. + if (nina_bsp_spi_transfer(args[i].data, NULL, args[i].size) != 0) { + goto error_out; + } + length += args[i].size + width; + } + + // Send END byte + padding to multiple of 4. + uint8_t cmdbuf_end[4] = {CMD_END, 0xFF, 0xFF, 0xFF}; + if (nina_bsp_spi_transfer(cmdbuf_end, NULL, 1 + (length % 4)) != 0) { + goto error_out; + } + + // All good + ret = 0; + +error_out: + debug_printf("\n"); + nina_bsp_spi_slave_deselect(); + return ret; +} + +static int nina_read_response(uint32_t cmd, uint32_t nvals, uint32_t width, nina_vals_t *vals) { + int ret = -1; + + debug_printf("nina_read_response(cmd 0x%x nvals %d width %d): ", cmd, nvals, width); + + // Read reply + if (nina_bsp_spi_slave_select(NINA_SSELECT_TIMEOUT) != 0) { + return -1; + } + + // Wait for CMD_START + if (nina_wait_for_cmd(CMD_START, NINA_RESPONSE_TIMEOUT) != 0) { + goto error_out; + } + + // Should return CMD + REPLY flag. + if (nina_bsp_spi_read_byte() != (cmd | CMD_REPLY)) { + goto error_out; + } + + // Sanity check the number of returned values. + // NOTE: This is to handle the special case for the scan command. + uint32_t rvals = nina_bsp_spi_read_byte(); + if (nvals > rvals) { + nvals = rvals; + } + + // Read return value(s). + for (uint32_t i = 0; i < nvals; i++) { + // Read return value size. + uint16_t bytes = nina_bsp_spi_read_byte(); + if (width == ARG_16BITS) { + bytes = (bytes << 8) | nina_bsp_spi_read_byte(); + } + + // Check the val fits the buffer. + if (*(vals[i].size) < bytes) { + goto error_out; + } + + // Read the returned value. + if (nina_bsp_spi_transfer(NULL, vals[i].data, bytes) != 0) { + goto error_out; + } + + // Set the size. + *(vals[i].size) = bytes; + } + + if (nina_bsp_spi_read_byte() != CMD_END) { + goto error_out; + } + + // All good + ret = 0; + +error_out: + debug_printf("\n"); + nina_bsp_spi_slave_deselect(); + return ret; +} + +static int nina_send_command_read_ack(uint32_t cmd, uint32_t nargs, uint32_t width, nina_args_t *args) { + uint16_t size = 1; + uint8_t rval = SPI_ERR; + if (nina_send_command(cmd, nargs, width, args) != 0 || + nina_read_response(cmd, 1, ARG_8BITS, NINA_VALS({&size, &rval})) != 0) { + return -1; + } + return rval; +} + +static int nina_send_command_read_vals(uint32_t cmd, uint32_t nargs, + uint32_t argsw, nina_args_t *args, uint32_t nvals, uint32_t valsw, nina_vals_t *vals) { + + if (nina_send_command(cmd, nargs, argsw, args) != 0 || + nina_read_response(cmd, nvals, valsw, vals) != 0) { + return -1; + } + return 0; +} + +static void nina_fix_mac_addr(uint8_t *mac) { + for (int i = 0; i < 3; i++) { + uint8_t b = mac[i]; + mac[i] = mac[5 - i]; + mac[5 - i] = b; + } +} + +int nina_init(void) { + // Initialize the BSP. + nina_bsp_init(); + return 0; +} + +int nina_deinit(void) { + return nina_bsp_deinit(); +} + +static int nina_connection_status() { + return nina_send_command_read_ack(NINA_CMD_CONN_STATUS, 0, ARG_8BITS, NULL); +} + +static int nina_socket_status(uint8_t fd) { + return nina_send_command_read_ack(NINA_CMD_SOCKET_STATE, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))); +} + +static int nina_server_socket_status(uint8_t fd) { + return nina_send_command_read_ack(NINA_CMD_SOCKET_STATE & 0xF9, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))); +} + +int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel) { + uint8_t status = NINA_STATUS_CONNECT_FAILED; + + if (key == NULL && security != NINA_SEC_OPEN) { + return -1; + } + + switch (security) { + case NINA_SEC_OPEN: + if (nina_send_command_read_ack(NINA_CMD_CONNECT_OPEN, + 1, ARG_8BITS, NINA_ARGS(ARG_STR(ssid))) != SPI_ACK) { + return -1; + } + break; + case NINA_SEC_WEP: + if (nina_send_command_read_ack(NINA_CMD_CONNECT_WEP, + 2, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_STR(key))) != SPI_ACK) { + return -1; + } + break; + case NINA_SEC_WPA_PSK: + if (nina_send_command_read_ack(NINA_CMD_CONNECT_WPA, + 3, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_BYTE(0), ARG_STR(key))) != SPI_ACK) { + return -1; + } + break; + default: + return -1; + } + + for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) { + status = nina_connection_status(); + if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) { + break; + } + + if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) { + break; + } + } + + return (status == NINA_STATUS_CONNECTED) ? 0 : -1; +} + +int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel) { + uint8_t status = NINA_STATUS_AP_FAILED; + + if ((key == NULL && security != NINA_SEC_OPEN) || + (security != NINA_SEC_OPEN && security != NINA_SEC_WEP)) { + return -1; + } + + switch (security) { + case NINA_SEC_OPEN: + if (nina_send_command_read_ack(NINA_CMD_START_AP_OPEN, + 2, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_BYTE(channel))) != SPI_ACK) { + return -1; + } + break; + case NINA_SEC_WEP: + if (nina_send_command_read_ack(NINA_CMD_START_AP_WEP, + 3, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_STR(key), ARG_BYTE(channel))) != SPI_ACK) { + return -1; + } + break; + default: + return -1; + } + + for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) { + status = nina_connection_status(); + if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) { + break; + } + + if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) { + break; + } + } + + return (status == NINA_STATUS_AP_LISTENING) ? 0 : -1; +} + +int nina_disconnect(void) { + if (nina_send_command_read_ack(NINA_CMD_DISCONNECT, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF))) != SPI_ACK) { + return -1; + } + return 0; +} + +int nina_isconnected(void) { + int status = nina_connection_status(); + if (status == -1) { + return -1; + } + return status == NINA_STATUS_CONNECTED; +} + +int nina_connected_sta(uint32_t *sta_ip) { + return -1; +} + +int nina_wait_for_sta(uint32_t *sta_ip, uint32_t timeout) { + return NINA_ERROR_TIMEOUT; +} + +int nina_ifconfig(nina_ifconfig_t *ifconfig, bool set) { + uint16_t ip_len = NINA_IPV4_ADDR_LEN; + uint16_t sub_len = NINA_IPV4_ADDR_LEN; + uint16_t gw_len = NINA_IPV4_ADDR_LEN; + uint16_t dns_len = NINA_IPV4_ADDR_LEN; + + if (set) { + if (nina_send_command_read_ack(NINA_CMD_SET_IF_CONFIG, + 4, ARG_8BITS, + NINA_ARGS( + ARG_BYTE(3), // Valid number of args. + {ip_len, ifconfig->ip_addr}, + {gw_len, ifconfig->gateway_addr}, + {sub_len, ifconfig->subnet_addr})) != 0) { + return -1; + } + + uint8_t dns2[4] = {8, 8, 8, 8}; + if (nina_send_command_read_ack(NINA_CMD_SET_DNS_CONFIG, + 3, ARG_8BITS, + NINA_ARGS( + ARG_BYTE(1), // Valid number of args. + {dns_len, ifconfig->dns_addr}, + {dns_len, dns2})) != SPI_ACK) { + return -1; + } + + } else { + if (nina_send_command_read_vals(NINA_CMD_GET_IF_CONFIG, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)), + 3, ARG_8BITS, + NINA_VALS( + {&ip_len, ifconfig->ip_addr}, + {&sub_len, ifconfig->subnet_addr}, + {&gw_len, ifconfig->gateway_addr})) != 0) { + return -1; + } + // No command to get DNS ? + memcpy(ifconfig->dns_addr, ifconfig->gateway_addr, NINA_IPV4_ADDR_LEN); + } + return 0; +} + +int nina_netinfo(nina_netinfo_t *netinfo) { + uint16_t rssi_len = 4; + uint16_t sec_len = 1; + uint16_t ssid_len = NINA_MAX_SSID_LEN; + uint16_t bssid_len = NINA_MAC_ADDR_LEN; + + if (nina_send_command_read_vals(NINA_CMD_GET_RSSI, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)), + 1, ARG_8BITS, NINA_VALS({&rssi_len, &netinfo->rssi})) != 0) { + return -1; + } + + if (nina_send_command_read_vals(NINA_CMD_GET_ENCRYPT, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)), + 1, ARG_8BITS, NINA_VALS({&sec_len, &netinfo->security})) != 0) { + return -1; + } + + if (nina_send_command_read_vals(NINA_CMD_GET_SSID, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)), + 1, ARG_8BITS, NINA_VALS({&ssid_len, &netinfo->ssid})) != 0) { + return -1; + } + + // Null terminate SSID. + netinfo->ssid[MIN((NINA_MAX_SSID_LEN - 1), ssid_len)] = 0; + + if (nina_send_command_read_vals(NINA_CMD_GET_BSSID, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)), + 1, ARG_8BITS, NINA_VALS({&bssid_len, &netinfo->bssid})) != 0) { + return -1; + } + + // The MAC address is read in reverse from the firmware. + nina_fix_mac_addr(netinfo->bssid); + + return 0; +} + +int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout) { + uint16_t sizes[NINA_MAX_NETWORK_LIST]; + char ssids[NINA_MAX_NETWORK_LIST][NINA_MAX_SSID_LEN]; + nina_vals_t vals[NINA_MAX_NETWORK_LIST]; + + // Initialize the values list. + for (int i = 0; i < NINA_MAX_NETWORK_LIST; i++) { + sizes[i] = NINA_MAX_SSID_LEN - 1; + memset(ssids[i], 0, NINA_MAX_SSID_LEN); + vals[i].size = &sizes[i]; + vals[i].data = ssids[i]; + } + + if (nina_send_command_read_ack(NINA_CMD_AP_START_SCAN, + 0, ARG_8BITS, NULL) != SPI_ACK) { + return -1; + } + + for (mp_uint_t start = mp_hal_ticks_ms(); ;) { + if (nina_send_command_read_vals(NINA_CMD_AP_SCAN_RESULT, + 0, ARG_8BITS, NULL, + NINA_MAX_NETWORK_LIST, ARG_8BITS, vals) != 0) { + return -1; + } + + if (ssids[0][0] != 0) { + // Found at least 1 network. + break; + } + + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { + // Timeout, no networks. + return NINA_ERROR_TIMEOUT; + } + + mp_hal_delay_ms(100); + } + + for (int i = 0; i < NINA_MAX_NETWORK_LIST; i++) { + uint16_t rssi_len = 4; + uint16_t sec_len = 1; + uint16_t chan_len = 1; + uint16_t bssid_len = NINA_MAC_ADDR_LEN; + nina_scan_result_t scan_result; + + if (ssids[i][0] == 0) { + break; + } + + // Set AP SSID + strncpy(scan_result.ssid, ssids[i], NINA_MAX_SSID_LEN); + + // Read AP RSSI + if (nina_send_command_read_vals(NINA_CMD_AP_GET_RSSI, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)), + 1, ARG_8BITS, NINA_VALS({&rssi_len, &scan_result.rssi})) != 0) { + return -1; + } + + // Read AP encryption type + if (nina_send_command_read_vals(NINA_CMD_AP_GET_ENCRYPT, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)), + 1, ARG_8BITS, NINA_VALS({&sec_len, &scan_result.security})) != 0) { + return -1; + } + + // Read AP channel + if (nina_send_command_read_vals(NINA_CMD_AP_GET_CHANNEL, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)), + 1, ARG_8BITS, NINA_VALS({&chan_len, &scan_result.channel})) != 0) { + return -1; + } + + // Read AP bssid + if (nina_send_command_read_vals(NINA_CMD_AP_GET_BSSID, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)), + 1, ARG_8BITS, NINA_VALS({&bssid_len, scan_result.bssid})) != 0) { + return -1; + } + + // The MAC address is read in reverse from the firmware. + nina_fix_mac_addr(scan_result.bssid); + + scan_callback(&scan_result, arg); + } + + return 0; +} + +int nina_get_rssi(void) { + uint16_t size = 4; + int32_t rssi = 0; + if (nina_send_command_read_vals(NINA_CMD_GET_RSSI, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)), + 1, ARG_8BITS, NINA_VALS({&size, &rssi})) != 0) { + return -1; + } + + return rssi; +} + +int nina_fw_version(uint8_t *fw_ver) { + uint16_t size = NINA_FW_VER_LEN; + if (nina_send_command_read_vals(NINA_CMD_GET_FW_VERSION, + 0, ARG_8BITS, NULL, + 1, ARG_8BITS, NINA_VALS({&size, fw_ver})) != 0) { + return -1; + } + return 0; +} + +int nina_set_hostname(const char *hostname) { + if (nina_send_command_read_ack(NINA_CMD_SET_HOSTNAME, + 1, ARG_8BITS, NINA_ARGS(ARG_STR(hostname))) != SPI_ACK) { + return -1; + } + return 0; +} + +int nina_gethostbyname(const char *name, uint8_t *out_ip) { + uint16_t size = 4; + + if (nina_send_command_read_ack(NINA_CMD_HOST_BY_NAME, + 1, ARG_8BITS, NINA_ARGS(ARG_STR(name))) != SPI_ACK) { + return -1; + } + + if (nina_send_command_read_vals(NINA_CMD_GET_HOST_BY_NAME, + 0, ARG_8BITS, NULL, + 1, ARG_8BITS, NINA_VALS({&size, out_ip})) != 0) { + return -1; + } + return 0; +} + +int nina_socket_socket(uint8_t type) { + uint16_t size = 1; + uint8_t sock = 0; + + if (nina_send_command_read_vals(NINA_CMD_SOCKET_OPEN, + 0, ARG_8BITS, NULL, + 1, ARG_8BITS, NINA_VALS({&size, &sock})) != 0) { + return -1; + } + return sock; +} + +int nina_socket_close(int fd) { + if (fd > 0 && fd < 255) { + if (nina_send_command_read_ack(NINA_CMD_SOCKET_CLOSE, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))) != SPI_ACK) { + return -1; + } + for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) { + if (nina_socket_status(fd) == SOCKET_STATE_CLOSED) { + break; + } + if ((mp_hal_ticks_ms() - start) >= 5000) { + return NINA_ERROR_TIMEOUT; + } + } + } + return 0; +} + +int nina_socket_bind(int fd, uint8_t *ip, uint16_t port, int type) { + if (nina_send_command_read_ack(NINA_CMD_SOCKET_BIND, + 3, ARG_8BITS, + NINA_ARGS( + ARG_SHORT(__REVSH(port)), + ARG_BYTE(fd), + ARG_BYTE(type))) != SPI_ACK) { + return -1; + } + + // Only TCP sockets' states should be checked. + if (type == NINA_SOCKET_TYPE_TCP && + nina_server_socket_status(fd) != SOCKET_STATE_LISTEN) { + return -1; + } + return 0; +} + +int nina_socket_listen(int fd, uint32_t backlog) { + return 0; // No listen ? +} + +int nina_socket_accept(int fd, uint8_t *ip, uint16_t *port, int *fd_out, uint32_t timeout) { + uint16_t size = 2; + uint16_t sock = NO_SOCKET_AVAIL; + + if (nina_server_socket_status(fd) != SOCKET_STATE_LISTEN) { + return -1; + } + + for (mp_uint_t start = mp_hal_ticks_ms(); sock == 0 || sock == NO_SOCKET_AVAIL; mp_hal_delay_ms(10)) { + if (nina_send_command_read_vals(NINA_CMD_SOCKET_ACCEPT, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)), + 1, ARG_8BITS, NINA_VALS({&size, &sock})) != 0) { + return -1; + } + + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { + return NINA_ERROR_TIMEOUT; + } + } + + uint16_t port_len = 2; + uint16_t ip_len = NINA_IPV4_ADDR_LEN; + if (nina_send_command_read_vals(NINA_CMD_SOCKET_REMOTE_ADDR, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(sock)), + 2, ARG_8BITS, NINA_VALS({&ip_len, ip}, {&port_len, port})) != 0) { + return -1; + } + *fd_out = sock; + *port = __REVSH(*port); + return 0; +} + +int nina_socket_connect(int fd, uint8_t *ip, uint16_t port, uint32_t timeout) { + if (nina_send_command_read_ack(NINA_CMD_SOCKET_CONNECT, + 4, ARG_8BITS, + NINA_ARGS( + ARG_WORD((*(uint32_t *)ip)), + ARG_SHORT(__REVSH(port)), + ARG_BYTE(fd), + ARG_BYTE(NINA_SOCKET_TYPE_TCP))) != SPI_ACK) { + return -1; + } + + for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) { + int state = nina_socket_status(fd); + if (state == -1) { + return -1; + } + + if (state == SOCKET_STATE_ESTABLISHED) { + break; + } + + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { + return NINA_ERROR_TIMEOUT; + } + } + + return 0; +} + +int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout) { + uint16_t size = 2; + uint16_t bytes = 0; + + if (nina_socket_status(fd) != SOCKET_STATE_ESTABLISHED) { + return -1; + } + + if (nina_send_command_read_vals(NINA_CMD_TCP_SEND, + 2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf}), + 1, ARG_8BITS, NINA_VALS({&size, &bytes})) != 0 || bytes <= 0) { + return -1; + } + + for (mp_uint_t start = mp_hal_ticks_ms(); ;) { + int resp = nina_send_command_read_ack(NINA_CMD_TCP_ACK, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))); + + if (resp == -1) { + return -1; + } + + if (resp == SPI_ACK) { + break; + } + + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { + return NINA_ERROR_TIMEOUT; + } + mp_hal_delay_ms(1); + } + + return bytes; +} + +int nina_socket_recv(int fd, uint8_t *buf, uint32_t len, uint32_t timeout) { + uint16_t bytes = 0; + + if (nina_socket_status(fd) != SOCKET_STATE_ESTABLISHED) { + return -1; + } + + for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) { + bytes = len; + if (nina_send_command_read_vals(NINA_CMD_TCP_RECV, + 2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)), + 1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) { + return -1; + } + + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { + return NINA_ERROR_TIMEOUT; + } + } + return bytes; +} + +// Check from the upper layer if the socket is bound, if not then auto-bind it first. +int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint32_t timeout) { + // TODO do we need to split the packet somewhere? + if (nina_send_command_read_ack(NINA_CMD_SOCKET_CONNECT, + 4, ARG_8BITS, + NINA_ARGS( + ARG_WORD((*(uint32_t *)ip)), + ARG_SHORT(__REVSH(port)), + ARG_BYTE(fd), + ARG_BYTE(NINA_SOCKET_TYPE_UDP))) != SPI_ACK) { + return -1; + } + + // Buffer length and socket number are passed as 16bits. + if (nina_send_command_read_ack(NINA_CMD_UDP_SEND, + 2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf})) != SPI_ACK) { + return -1; + } + + if (nina_send_command_read_ack(NINA_CMD_UDP_ACK, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))) != SPI_ACK) { + return -1; + } + + return 0; +} + +// Check from the upper layer if the socket is bound, if not then auto-bind it first. +int nina_socket_recvfrom(int fd, uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t *port, uint32_t timeout) { + uint16_t bytes = 0; + uint16_t port_len = 2; + uint16_t ip_len = NINA_IPV4_ADDR_LEN; + + for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) { + bytes = len; + if (nina_send_command_read_vals(NINA_CMD_UDP_RECV, + 2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)), + 1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) { + return -1; + } + + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { + return NINA_ERROR_TIMEOUT; + } + } + if (nina_send_command_read_vals(NINA_CMD_SOCKET_REMOTE_ADDR, + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)), + 2, ARG_8BITS, NINA_VALS({&ip_len, ip}, {&port_len, port})) != 0) { + return -1; + } + + return bytes; +} + +int nina_socket_setsockopt(int fd, uint32_t level, uint32_t opt, const void *optval, uint32_t optlen) { + return -1; +} + +#endif // MICROPY_PY_NINAW10 diff --git a/drivers/ninaw10/nina_wifi_drv.h b/drivers/ninaw10/nina_wifi_drv.h new file mode 100644 index 000000000..d8c55f5e6 --- /dev/null +++ b/drivers/ninaw10/nina_wifi_drv.h @@ -0,0 +1,120 @@ +/* + * This file is part of the OpenMV project, https://openmv.io. + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * 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. + * + * NINA-W10 WiFi driver. + */ +#ifndef MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H +#define MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H + +#define NINA_FW_VER_LEN (6) +#define NINA_IPV4_ADDR_LEN (4) +#define NINA_MAC_ADDR_LEN (6) +#define NINA_MAX_SSID_LEN (32) +#define NINA_MAX_WEP_LEN (13) +#define NINA_MAX_WPA_LEN (63) +#define NINA_MAX_NETWORK_LIST (10) +#define NINA_MAX_SOCKET (10) + +#define NINA_FW_VER_MAJOR (1) +#define NINA_FW_VER_MINOR (4) +#define NINA_FW_VER_PATCH (8) + +#define NINA_FW_VER_MAJOR_OFFS (0) +#define NINA_FW_VER_MINOR_OFFS (2) +#define NINA_FW_VER_PATCH_OFFS (4) + +typedef enum { + NINA_SEC_INVALID = 0, + NINA_SEC_OPEN, + NINA_SEC_WPA_PSK, + NINA_SEC_WEP +} nina_security_t; + +typedef enum { + NINA_SOCKET_TYPE_TCP = 0, + NINA_SOCKET_TYPE_UDP, + NINA_SOCKET_TYPE_TLS, + NINA_SOCKET_TYPE_UDP_MULTICAST, + NINA_SOCKET_TYPE_TLS_BEARSSL +} nina_socket_type_t; + +typedef enum { + NINA_ERROR_IO = -1, + NINA_ERROR_TIMEOUT = -2, +} nina_error_t; + +typedef struct { + uint8_t ip_addr[NINA_IPV4_ADDR_LEN]; + uint8_t subnet_addr[NINA_IPV4_ADDR_LEN]; + uint8_t gateway_addr[NINA_IPV4_ADDR_LEN]; + uint8_t dns_addr[NINA_IPV4_ADDR_LEN]; +} nina_ifconfig_t; + +typedef struct { + int32_t rssi; + uint8_t security; + uint8_t channel; + uint8_t bssid[NINA_MAC_ADDR_LEN]; + char ssid[NINA_MAX_SSID_LEN]; +} nina_scan_result_t; + +typedef struct { + int32_t rssi; + uint8_t security; + char ssid[NINA_MAX_SSID_LEN]; + uint8_t bssid[NINA_MAC_ADDR_LEN]; +} nina_netinfo_t; + +typedef int (*nina_scan_callback_t)(nina_scan_result_t *, void *); + +int nina_init(void); +int nina_deinit(void); +int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel); +int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel); +int nina_disconnect(void); +int nina_isconnected(void); +int nina_connected_sta(uint32_t *sta_ip); +int nina_wait_for_sta(uint32_t *sta_ip, uint32_t timeout); +int nina_ifconfig(nina_ifconfig_t *ifconfig, bool set); +int nina_netinfo(nina_netinfo_t *netinfo); +int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout); +int nina_get_rssi(void); +int nina_fw_version(uint8_t *fw_ver); +int nina_set_hostname(const char *name); +int nina_gethostbyname(const char *name, uint8_t *out_ip); +int nina_socket_socket(uint8_t type); +int nina_socket_close(int fd); +int nina_socket_bind(int fd, uint8_t *ip, uint16_t port, int type); +int nina_socket_listen(int fd, uint32_t backlog); +int nina_socket_accept(int fd, uint8_t *ip, uint16_t *port, int *fd_out, uint32_t timeout); +int nina_socket_connect(int fd, uint8_t *ip, uint16_t port, uint32_t timeout); +int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout); +int nina_socket_recv(int fd, uint8_t *buf, uint32_t len, uint32_t timeout); +int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint32_t timeout); +int nina_socket_recvfrom(int fd, uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t *port, uint32_t timeout); +int nina_socket_setsockopt(int fd, uint32_t level, uint32_t opt, const void *optval, uint32_t optlen); + +#endif // MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H diff --git a/examples/embedding/mpconfigport_minimal.h b/examples/embedding/mpconfigport_minimal.h index b5ffd376a..07180a322 100644 --- a/examples/embedding/mpconfigport_minimal.h +++ b/examples/embedding/mpconfigport_minimal.h @@ -45,7 +45,6 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) #define MICROPY_STREAMS_NON_BLOCK (0) #define MICROPY_OPT_COMPUTED_GOTO (0) -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) #define MICROPY_CAN_OVERRIDE_BUILTINS (0) #define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) #define MICROPY_CPYTHON_COMPAT (0) diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c index 4e81e21fe..e56e488b1 100644 --- a/extmod/btstack/modbluetooth_btstack.c +++ b/extmod/btstack/modbluetooth_btstack.c @@ -1265,13 +1265,13 @@ int mp_bluetooth_gap_scan_stop(void) { return 0; } -int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) { +int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us) { DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n"); uint16_t conn_scan_interval = 60000 / 625; uint16_t conn_scan_window = 30000 / 625; - uint16_t conn_interval_min = 10000 / 1250; - uint16_t conn_interval_max = 30000 / 1250; + uint16_t conn_interval_min = (min_conn_interval_us ? min_conn_interval_us : 10000) / 1250; + uint16_t conn_interval_max = (max_conn_interval_us ? max_conn_interval_us : 30000) / 1250; uint16_t conn_latency = 4; uint16_t supervision_timeout = duration_ms / 10; // default = 720 uint16_t min_ce_length = 10000 / 625; @@ -1284,6 +1284,11 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, return btstack_error_to_errno(gap_connect(btstack_addr, addr_type)); } +int mp_bluetooth_gap_peripheral_connect_cancel(void) { + DEBUG_printf("mp_bluetooth_gap_peripheral_connect_cancel\n"); + return btstack_error_to_errno(gap_connect_cancel()); +} + #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake index c6b45b0d3..67f7d8fd3 100644 --- a/extmod/extmod.cmake +++ b/extmod/extmod.cmake @@ -10,11 +10,13 @@ set(MICROPY_SOURCE_EXTMOD ${MICROPY_EXTMOD_DIR}/machine_i2c.c ${MICROPY_EXTMOD_DIR}/machine_mem.c ${MICROPY_EXTMOD_DIR}/machine_pulse.c + ${MICROPY_EXTMOD_DIR}/machine_pwm.c ${MICROPY_EXTMOD_DIR}/machine_signal.c ${MICROPY_EXTMOD_DIR}/machine_spi.c ${MICROPY_EXTMOD_DIR}/modbluetooth.c ${MICROPY_EXTMOD_DIR}/modbtree.c ${MICROPY_EXTMOD_DIR}/modframebuf.c + ${MICROPY_EXTMOD_DIR}/modnetwork.c ${MICROPY_EXTMOD_DIR}/modonewire.c ${MICROPY_EXTMOD_DIR}/moduasyncio.c ${MICROPY_EXTMOD_DIR}/modubinascii.c @@ -23,9 +25,11 @@ set(MICROPY_SOURCE_EXTMOD ${MICROPY_EXTMOD_DIR}/moduhashlib.c ${MICROPY_EXTMOD_DIR}/moduheapq.c ${MICROPY_EXTMOD_DIR}/modujson.c + ${MICROPY_EXTMOD_DIR}/moduplatform.c ${MICROPY_EXTMOD_DIR}/modurandom.c ${MICROPY_EXTMOD_DIR}/modure.c ${MICROPY_EXTMOD_DIR}/moduselect.c + ${MICROPY_EXTMOD_DIR}/modusocket.c ${MICROPY_EXTMOD_DIR}/modussl_axtls.c ${MICROPY_EXTMOD_DIR}/modussl_mbedtls.c ${MICROPY_EXTMOD_DIR}/modutimeq.c diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index 44161fbbb..b2e39c534 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -33,7 +33,7 @@ #include "py/runtime.h" #include "extmod/machine_i2c.h" -#if MICROPY_PY_MACHINE_I2C +#if MICROPY_PY_MACHINE_SOFTI2C typedef mp_machine_soft_i2c_obj_t machine_i2c_obj_t; @@ -240,9 +240,13 @@ int mp_machine_soft_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n return transfer_ret; } +#endif // MICROPY_PY_MACHINE_SOFTI2C + /******************************************************************************/ // Generic helper functions +#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C + // 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; @@ -628,9 +632,13 @@ STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = { }; MP_DEFINE_CONST_DICT(mp_machine_i2c_locals_dict, machine_i2c_locals_dict_table); +#endif // MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C + /******************************************************************************/ // Implementation of soft I2C +#if MICROPY_PY_MACHINE_SOFTI2C + STATIC void mp_machine_soft_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { mp_machine_soft_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "SoftI2C(scl=" MP_HAL_PIN_FMT ", sda=" MP_HAL_PIN_FMT ", freq=%u)", @@ -711,4 +719,4 @@ const mp_obj_type_t mp_machine_soft_i2c_type = { .locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict, }; -#endif // MICROPY_PY_MACHINE_I2C +#endif // MICROPY_PY_MACHINE_SOFTI2C diff --git a/extmod/machine_pwm.c b/extmod/machine_pwm.c new file mode 100644 index 000000000..ddf49c135 --- /dev/null +++ b/extmod/machine_pwm.c @@ -0,0 +1,143 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#if MICROPY_PY_MACHINE_PWM + +#include "extmod/machine_pwm.h" + +#ifdef MICROPY_PY_MACHINE_PWM_INCLUDEFILE +#include MICROPY_PY_MACHINE_PWM_INCLUDEFILE +#endif + +#if MICROPY_PY_MACHINE_PWM_INIT +STATIC mp_obj_t machine_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + mp_machine_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pwm_init_obj, 1, machine_pwm_init); +#endif + +// PWM.deinit() +STATIC mp_obj_t machine_pwm_deinit(mp_obj_t self_in) { + machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_machine_pwm_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_deinit_obj, machine_pwm_deinit); + +// PWM.freq([value]) +STATIC mp_obj_t machine_pwm_freq(size_t n_args, const mp_obj_t *args) { + machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // Get frequency. + return mp_machine_pwm_freq_get(self); + } else { + // Set the frequency. + mp_int_t freq = mp_obj_get_int(args[1]); + mp_machine_pwm_freq_set(self, freq); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_freq_obj, 1, 2, machine_pwm_freq); + +#if MICROPY_PY_MACHINE_PWM_DUTY +// PWM.duty([duty]) +STATIC mp_obj_t machine_pwm_duty(size_t n_args, const mp_obj_t *args) { + machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // Get duty cycle. + return mp_machine_pwm_duty_get(self); + } else { + // Set duty cycle. + mp_int_t duty = mp_obj_get_int(args[1]); + mp_machine_pwm_duty_set(self, duty); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_obj, 1, 2, machine_pwm_duty); +#endif + +#if MICROPY_PY_MACHINE_PWM_DUTY_U16_NS + +// PWM.duty_u16([value]) +STATIC mp_obj_t machine_pwm_duty_u16(size_t n_args, const mp_obj_t *args) { + machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // Get duty cycle. + return mp_machine_pwm_duty_get_u16(self); + } else { + // Set duty cycle. + mp_int_t duty_u16 = mp_obj_get_int(args[1]); + mp_machine_pwm_duty_set_u16(self, duty_u16); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_u16_obj, 1, 2, machine_pwm_duty_u16); + +// PWM.duty_ns([value]) +STATIC mp_obj_t machine_pwm_duty_ns(size_t n_args, const mp_obj_t *args) { + machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // Get duty cycle. + return mp_machine_pwm_duty_get_ns(self); + } else { + // Set duty cycle. + mp_int_t duty_ns = mp_obj_get_int(args[1]); + mp_machine_pwm_duty_set_ns(self, duty_ns); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_ns_obj, 1, 2, machine_pwm_duty_ns); + +#endif + +STATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = { + #if MICROPY_PY_MACHINE_PWM_INIT + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pwm_init_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_pwm_freq_obj) }, + #if MICROPY_PY_MACHINE_PWM_DUTY + { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&machine_pwm_duty_obj) }, + #endif + #if MICROPY_PY_MACHINE_PWM_DUTY_U16_NS + { MP_ROM_QSTR(MP_QSTR_duty_u16), MP_ROM_PTR(&machine_pwm_duty_u16_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty_ns), MP_ROM_PTR(&machine_pwm_duty_ns_obj) }, + #endif +}; +STATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict, machine_pwm_locals_dict_table); + +const mp_obj_type_t machine_pwm_type = { + { &mp_type_type }, + .name = MP_QSTR_PWM, + .print = mp_machine_pwm_print, + .make_new = mp_machine_pwm_make_new, + .locals_dict = (mp_obj_dict_t *)&machine_pwm_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE_PWM diff --git a/extmod/machine_pwm.h b/extmod/machine_pwm.h new file mode 100644 index 000000000..f0953014c --- /dev/null +++ b/extmod/machine_pwm.h @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H +#define MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H + +#include "py/obj.h" + +// A port must provide this type, but it's otherwise opaque. +typedef struct _machine_pwm_obj_t machine_pwm_obj_t; + +// This PWM class is implemented by machine_pwm.c. +extern const mp_obj_type_t machine_pwm_type; + +// A port must provide implementations of these low-level PWM functions, either as global +// linker symbols, or included directly if MICROPY_PY_MACHINE_PWM_INCLUDEFILE is defined. +#ifndef MICROPY_PY_MACHINE_PWM_INCLUDEFILE +void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); +void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +void mp_machine_pwm_deinit(machine_pwm_obj_t *self); +mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self); +void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq); +mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self); +void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty); +mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self); +void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16); +mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self); +void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns); +#endif + +#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c index c951a5137..ae5e6677d 100644 --- a/extmod/machine_spi.c +++ b/extmod/machine_spi.c @@ -30,8 +30,6 @@ #include "py/runtime.h" #include "extmod/machine_spi.h" -#if MICROPY_PY_MACHINE_SPI - // if a port didn't define MSB/LSB constants then provide them #ifndef MICROPY_PY_MACHINE_SPI_MSB #define MICROPY_PY_MACHINE_SPI_MSB (0) @@ -41,6 +39,8 @@ /******************************************************************************/ // MicroPython bindings for generic machine.SPI +#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI + STATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]); mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)s->type->protocol; @@ -115,12 +115,15 @@ STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB) }, { MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB) }, }; - MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table); +#endif // MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI + /******************************************************************************/ // Implementation of soft SPI +#if MICROPY_PY_MACHINE_SOFTSPI + STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) { #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) { @@ -258,4 +261,4 @@ const mp_obj_type_t mp_machine_soft_spi_type = { .locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict, }; -#endif // MICROPY_PY_MACHINE_SPI +#endif // MICROPY_PY_MACHINE_SOFTSPI diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index cb153f70e..c4b9675ce 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -215,7 +215,9 @@ STATIC mp_int_t bluetooth_uuid_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bu return 0; } -#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS && MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS + +#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) { assert(ringbuf_free(ringbuf) >= (size_t)uuid->type + 1); ringbuf_put(ringbuf, uuid->type); @@ -223,7 +225,9 @@ STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) ringbuf_put(ringbuf, uuid->data[i]); } } +#endif +#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) { assert(ringbuf_avail(ringbuf) >= 1); uuid->type = ringbuf_get(ringbuf); @@ -232,7 +236,9 @@ STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) uuid->data[i] = ringbuf_get(ringbuf); } } -#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE +#endif + +#endif // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS const mp_obj_type_t mp_type_bluetooth_uuid = { { &mp_type_type }, @@ -630,6 +636,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_register_services_obj, blue #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) { + if (n_args == 2) { + if (args[1] == mp_const_none) { + int err = mp_bluetooth_gap_peripheral_connect_cancel(); + return bluetooth_handle_errno(err); + } + mp_raise_TypeError(MP_ERROR_TEXT("invalid addr")); + } 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); @@ -637,14 +650,22 @@ STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) { mp_raise_ValueError(MP_ERROR_TEXT("invalid addr")); } mp_int_t scan_duration_ms = MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS; - if (n_args == 4) { + mp_int_t min_conn_interval_us = 0; + mp_int_t max_conn_interval_us = 0; + if (n_args >= 4 && args[3] != mp_const_none) { scan_duration_ms = mp_obj_get_int(args[3]); } + if (n_args >= 5 && args[4] != mp_const_none) { + min_conn_interval_us = mp_obj_get_int(args[4]); + } + if (n_args >= 6 && args[5] != mp_const_none) { + max_conn_interval_us = mp_obj_get_int(args[5]); + } - int err = mp_bluetooth_gap_peripheral_connect(addr_type, bufinfo.buf, scan_duration_ms); + int err = mp_bluetooth_gap_peripheral_connect(addr_type, bufinfo.buf, scan_duration_ms, min_conn_interval_us, max_conn_interval_us); 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_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 2, 6, bluetooth_ble_gap_connect); STATIC mp_obj_t bluetooth_ble_gap_scan(size_t n_args, const mp_obj_t *args) { // Default is indefinite scan, with the NimBLE "background scan" interval and window. diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 43519e594..52053045f 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -370,10 +370,14 @@ int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_ 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); +int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us); + +// Cancel in-progress connection to a peripheral. +int mp_bluetooth_gap_peripheral_connect_cancel(void); #endif #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT + // Find all primary services on the connected peripheral. int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid); diff --git a/ports/stm32/modnetwork.c b/extmod/modnetwork.c similarity index 78% rename from ports/stm32/modnetwork.c rename to extmod/modnetwork.c index 06c4eb05d..1f242de86 100644 --- a/ports/stm32/modnetwork.c +++ b/extmod/modnetwork.c @@ -32,55 +32,16 @@ #include "py/runtime.h" #include "py/mphal.h" #include "shared/netutils/netutils.h" -#include "systick.h" -#include "pendsv.h" #include "modnetwork.h" #if MICROPY_PY_NETWORK #if MICROPY_PY_LWIP - #include "lwip/netif.h" #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" - -// 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(); -} - -STATIC void pyb_lwip_poll(void) { - #if MICROPY_PY_WIZNET5K - // Poll the NIC for incoming data - wiznet5k_poll(); - #endif - - // Run the lwIP internal updates - 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); - } - - #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 /// \module network - network configuration @@ -124,28 +85,14 @@ 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_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) }, - #endif - #if MICROPY_PY_CC3K - { MP_ROM_QSTR(MP_QSTR_CC3K), MP_ROM_PTR(&mod_network_nic_type_cc3k) }, - #endif - { MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) }, + // Defined per port in mpconfigport.h + MICROPY_PORT_NETWORK_INTERFACES + // 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 + { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(MOD_NETWORK_STA_IF) }, + { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(MOD_NETWORK_AP_IF) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table); diff --git a/ports/stm32/modnetwork.h b/extmod/modnetwork.h similarity index 86% rename from ports/stm32/modnetwork.h rename to extmod/modnetwork.h index 0b6d0c4a7..bbf80bc47 100644 --- a/ports/stm32/modnetwork.h +++ b/extmod/modnetwork.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STM32_MODNETWORK_H -#define MICROPY_INCLUDED_STM32_MODNETWORK_H +#ifndef MICROPY_INCLUDED_MODNETWORK_H +#define MICROPY_INCLUDED_MODNETWORK_H #define MOD_NETWORK_IPADDR_BUF_SIZE (4) @@ -35,18 +35,13 @@ #define MOD_NETWORK_SOCK_DGRAM (2) #define MOD_NETWORK_SOCK_RAW (3) +#define MOD_NETWORK_STA_IF (0) +#define MOD_NETWORK_AP_IF (1) + #if MICROPY_PY_LWIP - struct netif; - -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; @@ -77,24 +72,23 @@ typedef struct _mod_network_socket_obj_t { mp_obj_base_t base; mp_obj_t nic; mod_network_nic_type_t *nic_type; - union { - struct { - uint8_t domain; - uint8_t type; - int8_t fileno; - } u_param; - mp_uint_t u_state; - }; + uint32_t domain : 5; + uint32_t type : 5; + uint32_t proto : 5; + uint32_t bound : 1; + int32_t fileno : 16; + #if MICROPY_PY_USOCKET_EXTENDED_STATE + // Extended socket state for NICs/ports that need it. + int32_t timeout; + void *state; + #endif } mod_network_socket_obj_t; -extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k; -extern const mod_network_nic_type_t mod_network_nic_type_cc3k; - -#endif +#endif // MICROPY_PY_LWIP void mod_network_init(void); void mod_network_deinit(void); void mod_network_register_nic(mp_obj_t nic); mp_obj_t mod_network_find_nic(const uint8_t *ip); -#endif // MICROPY_INCLUDED_STM32_MODNETWORK_H +#endif // MICROPY_INCLUDED_MODNETWORK_H diff --git a/extmod/modonewire.c b/extmod/modonewire.c index 6abe3dfad..8b3426815 100644 --- a/extmod/modonewire.c +++ b/extmod/modonewire.c @@ -30,6 +30,8 @@ #include "py/obj.h" #include "py/mphal.h" +#if MICROPY_PY_ONEWIRE + /******************************************************************************/ // Low-level 1-Wire routines @@ -160,3 +162,5 @@ const mp_obj_module_t mp_module_onewire = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t *)&onewire_module_globals, }; + +#endif // MICROPY_PY_ONEWIRE diff --git a/extmod/moduplatform.c b/extmod/moduplatform.c new file mode 100644 index 000000000..820feb312 --- /dev/null +++ b/extmod/moduplatform.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * + * 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/objtuple.h" +#include "py/objstr.h" +#include "py/mphal.h" +#include "genhdr/mpversion.h" + +#if MICROPY_PY_UPLATFORM + +// platform - Access to underlying platform's identifying data + +// TODO: Add more architectures, compilers and libraries. +// See: https://sourceforge.net/p/predef/wiki/Home/ + +#if defined(__ARM_ARCH) +#define PLATFORM_ARCH "arm" +#elif defined(__x86_64__) || defined(_WIN64) +#define PLATFORM_ARCH "x86_64" +#elif defined(__i386__) || defined(_M_IX86) +#define PLATFORM_ARCH "x86" +#elif defined(__xtensa__) || defined(_M_IX86) +#define PLATFORM_ARCH "xtensa" +#else +#define PLATFORM_ARCH "" +#endif + +#if defined(__GNUC__) +#define PLATFORM_COMPILER \ + "GCC " \ + MP_STRINGIFY(__GNUC__) "." \ + MP_STRINGIFY(__GNUC_MINOR__) "." \ + MP_STRINGIFY(__GNUC_PATCHLEVEL__) +#elif defined(__ARMCC_VERSION) +#define PLATFORM_COMPILER \ + "ARMCC " \ + MP_STRINGIFY((__ARMCC_VERSION / 1000000)) "." \ + MP_STRINGIFY((__ARMCC_VERSION / 10000 % 100)) "." \ + MP_STRINGIFY((__ARMCC_VERSION % 10000)) +#elif defined(_MSC_VER) +#if defined(_WIN64) +#define COMPILER_BITS "64 bit" +#elif defined(_M_IX86) +#define COMPILER_BITS "32 bit" +#else +#define COMPILER_BITS "" +#endif +#define PLATFORM_COMPILER \ + "MSC v." MP_STRINGIFY(_MSC_VER) " " COMPILER_BITS +#else +#define PLATFORM_COMPILER "" +#endif + +#if defined(__GLIBC__) +#define PLATFORM_LIBC_LIB "glibc" +#define PLATFORM_LIBC_VER \ + MP_STRINGIFY(__GLIBC__) "." \ + MP_STRINGIFY(__GLIBC_MINOR__) +#elif defined(__NEWLIB__) +#define PLATFORM_LIBC_LIB "newlib" +#define PLATFORM_LIBC_VER _NEWLIB_VERSION +#else +#define PLATFORM_LIBC_LIB "" +#define PLATFORM_LIBC_VER "" +#endif + +#if defined(__linux) +#define PLATFORM_SYSTEM "Linux" +#elif defined(__unix__) +#define PLATFORM_SYSTEM "Unix" +#elif defined(__CYGWIN__) +#define PLATFORM_SYSTEM "Cygwin" +#elif defined(_WIN32) +#define PLATFORM_SYSTEM "Windows" +#else +#define PLATFORM_SYSTEM "MicroPython" +#endif + +#ifndef MICROPY_PLATFORM_VERSION +#define MICROPY_PLATFORM_VERSION "" +#endif + +STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, PLATFORM_SYSTEM "-" MICROPY_VERSION_STRING "-" \ + PLATFORM_ARCH "-" MICROPY_PLATFORM_VERSION "-with-" PLATFORM_LIBC_LIB "" PLATFORM_LIBC_VER); +STATIC const MP_DEFINE_STR_OBJ(info_python_compiler_obj, PLATFORM_COMPILER); +STATIC const MP_DEFINE_STR_OBJ(info_libc_lib_obj, PLATFORM_LIBC_LIB); +STATIC const MP_DEFINE_STR_OBJ(info_libc_ver_obj, PLATFORM_LIBC_VER); +STATIC const mp_rom_obj_tuple_t info_libc_tuple_obj = { + {&mp_type_tuple}, 2, {MP_ROM_PTR(&info_libc_lib_obj), MP_ROM_PTR(&info_libc_ver_obj)} +}; + +STATIC mp_obj_t platform_platform(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return MP_OBJ_FROM_PTR(&info_platform_obj); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_platform_obj, 0, platform_platform); + +STATIC mp_obj_t platform_python_compiler(void) { + return MP_OBJ_FROM_PTR(&info_python_compiler_obj); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(platform_python_compiler_obj, platform_python_compiler); + +STATIC mp_obj_t platform_libc_ver(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return MP_OBJ_FROM_PTR(&info_libc_tuple_obj); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_libc_ver_obj, 0, platform_libc_ver); + +STATIC const mp_rom_map_elem_t modplatform_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uplatform) }, + { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_platform_obj) }, + { MP_ROM_QSTR(MP_QSTR_python_compiler), MP_ROM_PTR(&platform_python_compiler_obj) }, + { MP_ROM_QSTR(MP_QSTR_libc_ver), MP_ROM_PTR(&platform_libc_ver_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(modplatform_globals, modplatform_globals_table); + +const mp_obj_module_t mp_module_uplatform = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&modplatform_globals, +}; + +#endif // MICROPY_PY_UPLATFORM diff --git a/extmod/modure.c b/extmod/modure.c index 738a2b984..36c987a80 100644 --- a/extmod/modure.c +++ b/extmod/modure.c @@ -454,11 +454,16 @@ const mp_obj_module_t mp_module_ure = { // only if module is enabled by config setting. #define re1_5_fatal(x) assert(!x) + #include "lib/re1.5/compilecode.c" -#if MICROPY_PY_URE_DEBUG -#include "lib/re1.5/dumpcode.c" -#endif #include "lib/re1.5/recursiveloop.c" #include "lib/re1.5/charclass.c" +#if MICROPY_PY_URE_DEBUG +// Make sure the output print statements go to the same output as other Python output. +#define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#include "lib/re1.5/dumpcode.c" +#undef printf +#endif + #endif // MICROPY_PY_URE diff --git a/ports/stm32/modusocket.c b/extmod/modusocket.c similarity index 85% rename from ports/stm32/modusocket.c rename to extmod/modusocket.c index c59fc8522..a42b3213f 100644 --- a/ports/stm32/modusocket.c +++ b/extmod/modusocket.c @@ -35,7 +35,7 @@ #include "shared/netutils/netutils.h" #include "modnetwork.h" -#if MICROPY_PY_USOCKET && !MICROPY_PY_LWIP +#if MICROPY_PY_NETWORK && MICROPY_PY_USOCKET && !MICROPY_PY_LWIP /******************************************************************************/ // socket class @@ -51,19 +51,26 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t s->base.type = &socket_type; s->nic = MP_OBJ_NULL; s->nic_type = NULL; - s->u_param.domain = MOD_NETWORK_AF_INET; - s->u_param.type = MOD_NETWORK_SOCK_STREAM; - s->u_param.fileno = -1; + s->domain = MOD_NETWORK_AF_INET; + s->type = MOD_NETWORK_SOCK_STREAM; + s->proto = 0; + s->bound = false; + s->fileno = -1; if (n_args >= 1) { - s->u_param.domain = mp_obj_get_int(args[0]); + s->domain = mp_obj_get_int(args[0]); if (n_args >= 2) { - s->u_param.type = mp_obj_get_int(args[1]); + s->type = mp_obj_get_int(args[1]); if (n_args >= 4) { - s->u_param.fileno = mp_obj_get_int(args[3]); + s->fileno = mp_obj_get_int(args[3]); } } } + #if MICROPY_PY_USOCKET_EXTENDED_STATE + s->timeout = 0; + s->state = NULL; + #endif + return MP_OBJ_FROM_PTR(s); } @@ -78,6 +85,13 @@ STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) { if (self->nic_type->socket(self, &_errno) != 0) { mp_raise_OSError(_errno); } + + #if MICROPY_PY_USOCKET_EXTENDED_STATE + // if a timeout was set before binding a NIC, call settimeout to reset it + if (self->timeout != 0 && self->nic_type->settimeout(self, self->timeout, &_errno) != 0) { + mp_raise_OSError(_errno); + } + #endif } } @@ -137,6 +151,17 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) { socket2->nic = MP_OBJ_NULL; socket2->nic_type = NULL; + // set the same address family, socket type and protocol as parent + socket2->domain = self->domain; + socket2->type = self->type; + socket2->proto = self->proto; + socket2->bound = false; + socket2->fileno = -1; + #if MICROPY_PY_USOCKET_EXTENDED_STATE + socket2->timeout = 0; + socket2->state = NULL; + #endif + // accept incoming connection uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; mp_uint_t port; @@ -310,10 +335,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_s // otherwise, timeout is in seconds STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->nic == MP_OBJ_NULL) { - // not connected - mp_raise_OSError(MP_ENOTCONN); - } mp_uint_t timeout; if (timeout_in == mp_const_none) { timeout = -1; @@ -324,9 +345,19 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { timeout = 1000 * mp_obj_get_int(timeout_in); #endif } - int _errno; - if (self->nic_type->settimeout(self, timeout, &_errno) != 0) { - mp_raise_OSError(_errno); + if (self->nic == MP_OBJ_NULL) { + #if MICROPY_PY_USOCKET_EXTENDED_STATE + // store the timeout in the socket state until a NIC is bound + self->timeout = timeout; + #else + // not connected + mp_raise_OSError(MP_ENOTCONN); + #endif + } else { + int _errno; + if (self->nic_type->settimeout(self, timeout, &_errno) != 0) { + mp_raise_OSError(_errno); + } } return mp_const_none; } @@ -356,10 +387,41 @@ STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, }; STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); +mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + return MP_STREAM_ERROR; + } + mp_int_t ret = self->nic_type->recv(self, (byte *)buf, size, errcode); + if (ret < 0) { + ret = MP_STREAM_ERROR; + *errcode = -(*errcode); // expects a positive error code + } + return ret; +} + +mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + return MP_STREAM_ERROR; + } + mp_int_t ret = self->nic_type->send(self, buf, size, errcode); + if (ret < 0) { + ret = MP_STREAM_ERROR; + *errcode = -(*errcode); // expects a positive error code + } + return ret; +} + mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); if (request == MP_STREAM_CLOSE) { @@ -380,6 +442,8 @@ mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int * } STATIC const mp_stream_p_t socket_stream_p = { + .read = socket_read, + .write = socket_write, .ioctl = socket_ioctl, .is_text = false, }; @@ -477,4 +541,4 @@ const mp_obj_module_t mp_module_usocket = { .globals = (mp_obj_dict_t *)&mp_module_usocket_globals, }; -#endif // MICROPY_PY_USOCKET && !MICROPY_PY_LWIP +#endif // MICROPY_PY_NETWORK && MICROPY_PY_USOCKET && !MICROPY_PY_LWIP diff --git a/extmod/mpbthci.h b/extmod/mpbthci.h index acb5b832b..699723803 100644 --- a/extmod/mpbthci.h +++ b/extmod/mpbthci.h @@ -45,6 +45,7 @@ int mp_bluetooth_hci_controller_wakeup(void); int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate); int mp_bluetooth_hci_uart_deinit(void); int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate); +int mp_bluetooth_hci_uart_any(void); int mp_bluetooth_hci_uart_readchar(void); int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len); diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c index a5ed5d5b8..d2383c718 100644 --- a/extmod/network_cyw43.c +++ b/extmod/network_cyw43.c @@ -43,8 +43,8 @@ typedef struct _network_cyw43_obj_t { 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 const network_cyw43_obj_t network_cyw43_wl_sta = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_STA }; +STATIC const network_cyw43_obj_t network_cyw43_wl_ap = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_AP }; 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); @@ -65,7 +65,7 @@ STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_pr status_str = "fail"; } mp_printf(print, "", - self->itf == 0 ? "STA" : "AP", + self->itf == CYW43_ITF_STA ? "STA" : "AP", status_str, netif->ip_addr.addr & 0xff, netif->ip_addr.addr >> 8 & 0xff, @@ -76,10 +76,10 @@ STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_pr 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); + if (n_args == 0 || mp_obj_get_int(args[0]) == MOD_NETWORK_STA_IF) { + return MP_OBJ_FROM_PTR(&network_cyw43_wl_sta); } else { - return MP_OBJ_FROM_PTR(&network_cyw43_wl1); + return MP_OBJ_FROM_PTR(&network_cyw43_wl_ap); } } diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c new file mode 100644 index 000000000..cba24ea94 --- /dev/null +++ b/extmod/network_ninaw10.c @@ -0,0 +1,595 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * + * 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. + * + * NINA-W10 Python module. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_NETWORK && MICROPY_PY_NETWORK_NINAW10 + +#include +#include +#include +#include + +#include "py/objtuple.h" +#include "py/objlist.h" +#include "py/stream.h" +#include "py/runtime.h" +#include "py/misc.h" +#include "py/mperrno.h" +#include "shared/netutils/netutils.h" +#include "extmod/modnetwork.h" + +#include "nina_wifi_drv.h" + +typedef struct _nina_obj_t { + mp_obj_base_t base; + bool active; + uint32_t itf; +} nina_obj_t; + +// For auto-binding UDP sockets +#define BIND_PORT_RANGE_MIN (65000) +#define BIND_PORT_RANGE_MAX (65535) + +static uint16_t bind_port = BIND_PORT_RANGE_MIN; +const mod_network_nic_type_t mod_network_nic_type_nina; +static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF}; +static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_AP_IF}; + +STATIC mp_obj_t network_ninaw10_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_t nina_obj; + if (n_args == 0 || mp_obj_get_int(args[0]) == MOD_NETWORK_STA_IF) { + nina_obj = MP_OBJ_FROM_PTR(&network_nina_wl_sta); + } else { + nina_obj = MP_OBJ_FROM_PTR(&network_nina_wl_ap); + } + // Register with network module + mod_network_register_nic(nina_obj); + return nina_obj; +} + +STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) { + nina_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 2) { + bool active = mp_obj_is_true(args[1]); + if (active) { + int error = 0; + if ((error = nina_init()) != 0) { + mp_raise_msg_varg(&mp_type_OSError, + MP_ERROR_TEXT("Failed to initialize Nina-W10 module, error: %d\n"), error); + } + // check firmware version + uint8_t fw_ver[NINA_FW_VER_LEN]; + if (nina_fw_version(fw_ver) != 0) { + nina_deinit(); + mp_raise_msg_varg(&mp_type_OSError, + MP_ERROR_TEXT("Failed to read firmware version, error: %d\n"), error); + } + // Check fw version matches the driver. + if ((fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48) != NINA_FW_VER_MAJOR || + (fw_ver[NINA_FW_VER_MINOR_OFFS] - 48) != NINA_FW_VER_MINOR || + (fw_ver[NINA_FW_VER_PATCH_OFFS] - 48) != NINA_FW_VER_PATCH) { + mp_printf(&mp_plat_print, + "Warning: firmware version mismatch, expected %d.%d.%d found: %d.%d.%d\n", + NINA_FW_VER_MAJOR, NINA_FW_VER_MINOR, NINA_FW_VER_PATCH, + fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48, + fw_ver[NINA_FW_VER_MINOR_OFFS] - 48, + fw_ver[NINA_FW_VER_PATCH_OFFS] - 48); + } + } else { + nina_deinit(); + } + self->active = active; + return mp_const_none; + } + return mp_obj_new_bool(self->active); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_active_obj, 1, 2, network_ninaw10_active); + +STATIC int nina_scan_callback(nina_scan_result_t *scan_result, void *arg) { + mp_obj_t scan_list = (mp_obj_t)arg; + mp_obj_t ap[6] = { + mp_obj_new_bytes((uint8_t *)scan_result->ssid, strlen(scan_result->ssid)), + mp_obj_new_bytes(scan_result->bssid, sizeof(scan_result->bssid)), + mp_obj_new_int(scan_result->channel), + mp_obj_new_int(scan_result->rssi), + mp_obj_new_int(scan_result->security), + MP_OBJ_NEW_SMALL_INT(1), // N + }; + mp_obj_list_append(scan_list, mp_obj_new_tuple(MP_ARRAY_SIZE(ap), ap)); + return 0; +} + +STATIC mp_obj_t network_ninaw10_scan(mp_obj_t self_in) { + mp_obj_t scan_list; + scan_list = mp_obj_new_list(0, NULL); + nina_scan(nina_scan_callback, scan_list, 10000); + return scan_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_scan_obj, network_ninaw10_scan); + +STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_essid, ARG_key, ARG_security, ARG_channel }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_essid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_key, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NINA_SEC_WPA_PSK} }, + { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + }; + + // parse args + nina_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); + + // get ssid + const char *ssid = mp_obj_str_get_str(args[ARG_essid].u_obj); + + if (strlen(ssid) == 0) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SSID can't be empty!")); + } + + // get key and sec + const char *key = NULL; + mp_uint_t security = NINA_SEC_OPEN; + + if (args[ARG_key].u_obj != mp_const_none) { + key = mp_obj_str_get_str(args[ARG_key].u_obj); + security = args[ARG_security].u_int; + } + + if (security != NINA_SEC_OPEN && strlen(key) == 0) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Key can't be empty!")); + } + + // Disconnect active connections first. + if (nina_isconnected()) { + nina_disconnect(); + } + + if (self->itf == MOD_NETWORK_STA_IF) { + // Initialize WiFi in Station mode. + if (nina_connect(ssid, security, key, 0) != 0) { + mp_raise_msg_varg(&mp_type_OSError, + MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"), ssid, security, key); + } + } else { + mp_uint_t channel = args[ARG_channel].u_int; + + if (security != NINA_SEC_OPEN && security != NINA_SEC_WEP) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("AP mode supports WEP security only.")); + } + + // Initialize WiFi in AP mode. + if (nina_start_ap(ssid, security, key, channel) != 0) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("failed to start in AP mode")); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_connect_obj, 1, network_ninaw10_connect); + +STATIC mp_obj_t network_ninaw10_disconnect(mp_obj_t self_in) { + nina_disconnect(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_disconnect_obj, network_ninaw10_disconnect); + +STATIC mp_obj_t network_ninaw10_isconnected(mp_obj_t self_in) { + return mp_obj_new_bool(nina_isconnected()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_isconnected_obj, network_ninaw10_isconnected); + +STATIC mp_obj_t network_ninaw10_ifconfig(size_t n_args, const mp_obj_t *args) { + nina_ifconfig_t ifconfig; + if (n_args == 1) { + // get ifconfig info + nina_ifconfig(&ifconfig, false); + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr(ifconfig.ip_addr, NETUTILS_BIG), + netutils_format_ipv4_addr(ifconfig.subnet_addr, NETUTILS_BIG), + netutils_format_ipv4_addr(ifconfig.gateway_addr, NETUTILS_BIG), + netutils_format_ipv4_addr(ifconfig.dns_addr, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else { + // set ifconfig info + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 4, &items); + netutils_parse_ipv4_addr(items[0], ifconfig.ip_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[1], ifconfig.subnet_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[2], ifconfig.gateway_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[3], ifconfig.dns_addr, NETUTILS_BIG); + nina_ifconfig(&ifconfig, true); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_ifconfig_obj, 1, 2, network_ninaw10_ifconfig); + +STATIC mp_obj_t network_ninaw10_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + nina_obj_t *self = MP_OBJ_TO_PTR(args[0]); + (void)self; + + if (kwargs->used == 0) { + // Get config value + if (n_args != 2) { + mp_raise_TypeError(MP_ERROR_TEXT("must query one param")); + } + + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_essid: { + nina_netinfo_t netinfo; + nina_netinfo(&netinfo); + return mp_obj_new_str(netinfo.ssid, strlen(netinfo.ssid)); + } + case MP_QSTR_security: { + nina_netinfo_t netinfo; + nina_netinfo(&netinfo); + return mp_obj_new_int(netinfo.security); + } + case MP_QSTR_mac: + case MP_QSTR_bssid: { + nina_netinfo_t netinfo; + nina_netinfo(&netinfo); + return mp_obj_new_bytes(netinfo.bssid, 6); + } + case MP_QSTR_fw_version: { + uint8_t fwver[NINA_FW_VER_LEN]; + nina_fw_version(fwver); + return mp_obj_new_tuple(3, (mp_obj_t []) { + mp_obj_new_int(fwver[NINA_FW_VER_MAJOR_OFFS] - 48), + mp_obj_new_int(fwver[NINA_FW_VER_MINOR_OFFS] - 48), + mp_obj_new_int(fwver[NINA_FW_VER_PATCH_OFFS] - 48) + }); + } + default: + mp_raise_ValueError(MP_ERROR_TEXT("unknown config param")); + } + } else { + if (self->itf != MOD_NETWORK_AP_IF) { + mp_raise_ValueError(MP_ERROR_TEXT("AP required")); + } + // Call connect to set WiFi access point. + return network_ninaw10_connect(n_args, args, kwargs); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_config_obj, 1, network_ninaw10_config); + +STATIC mp_obj_t network_ninaw10_status(size_t n_args, const mp_obj_t *args) { + nina_obj_t *self = MP_OBJ_TO_PTR(args[0]); + (void)self; + + if (n_args == 1) { + // no arguments: return link status + return mp_obj_new_bool(nina_isconnected()); + } + + // Query parameter. + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_rssi: { + nina_netinfo_t netinfo; + nina_netinfo(&netinfo); + return mp_obj_new_int(netinfo.rssi); + } + case MP_QSTR_stations: { + if (self->itf != MOD_NETWORK_AP_IF) { + mp_raise_ValueError(MP_ERROR_TEXT("AP required")); + } + uint32_t sta_ip = 0; + mp_obj_t sta_list = mp_obj_new_list(0, NULL); + if (nina_connected_sta(&sta_ip) == 0) { + mp_obj_list_append(sta_list, + netutils_format_inet_addr((uint8_t *)&sta_ip, 0, NETUTILS_BIG)); + } + return sta_list; + } + } + + mp_raise_ValueError(MP_ERROR_TEXT("unknown status param")); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_status_obj, 1, 2, network_ninaw10_status); + +STATIC int network_ninaw10_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) { + return nina_gethostbyname(name, out_ip); +} + +STATIC int network_ninaw10_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { + uint8_t type; + + if (socket->domain != MOD_NETWORK_AF_INET) { + *_errno = MP_EAFNOSUPPORT; + return -1; + } + + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: + type = NINA_SOCKET_TYPE_TCP; + break; + + case MOD_NETWORK_SOCK_DGRAM: + type = NINA_SOCKET_TYPE_UDP; + break; + + default: + *_errno = MP_EINVAL; + return -1; + } + + // open socket + int fd = nina_socket_socket(type); + if (fd < 0) { + *_errno = fd; + return -1; + } + + // set socket state + socket->fileno = fd; + socket->bound = false; + return 0; +} + +STATIC void network_ninaw10_socket_close(mod_network_socket_obj_t *socket) { + if (socket->fileno >= 0) { + nina_socket_close(socket->fileno); + socket->fileno = -1; // Mark socket FD as invalid + } +} + +STATIC int network_ninaw10_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { + uint8_t type; + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: + type = NINA_SOCKET_TYPE_TCP; + break; + + case MOD_NETWORK_SOCK_DGRAM: + type = NINA_SOCKET_TYPE_UDP; + break; + + default: + *_errno = MP_EINVAL; + return -1; + } + + int ret = nina_socket_bind(socket->fileno, ip, port, type); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + + // Mark socket as bound to avoid auto-binding. + socket->bound = true; + return 0; +} + +STATIC int network_ninaw10_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) { + int ret = nina_socket_listen(socket->fileno, backlog); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return 0; +} + +STATIC int network_ninaw10_socket_accept(mod_network_socket_obj_t *socket, + mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) { + int fd = 0; + // Call accept. + int ret = nina_socket_accept(socket->fileno, ip, (uint16_t *)port, &fd, socket->timeout); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + + // set socket state + socket2->fileno = fd; + socket2->bound = false; + return 0; +} + +STATIC int network_ninaw10_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { + int ret = nina_socket_connect(socket->fileno, ip, port, socket->timeout); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return 0; +} + +STATIC mp_uint_t network_ninaw10_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { + int ret = nina_socket_send(socket->fileno, buf, len, socket->timeout); + if (ret == NINA_ERROR_TIMEOUT) { + // The socket is Not closed on timeout when calling functions that accept a timeout. + *_errno = MP_ETIMEDOUT; + return -1; + } else if (ret < 0) { + // Close the socket on any other errors. + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return ret; +} + +STATIC mp_uint_t network_ninaw10_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) { + int ret = 0; + if (socket->type == MOD_NETWORK_SOCK_DGRAM) { + byte ip[4]; + uint16_t port; + ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, &port, socket->timeout); + } else { + ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout); + } + + if (ret == NINA_ERROR_TIMEOUT) { + // The socket is Not closed on timeout when calling functions that accept a timeout. + *_errno = MP_ETIMEDOUT; + return -1; + } else if (ret < 0) { + // Close the socket on any other errors. + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return ret; +} + +STATIC mp_uint_t network_ninaw10_socket_auto_bind(mod_network_socket_obj_t *socket, int *_errno) { + if (socket->bound == false) { + if (network_ninaw10_socket_bind(socket, NULL, bind_port, _errno) != 0) { + return -1; + } + bind_port++; + bind_port = MIN(MAX(bind_port, BIND_PORT_RANGE_MIN), BIND_PORT_RANGE_MAX); + } + return 0; +} + +STATIC mp_uint_t network_ninaw10_socket_sendto(mod_network_socket_obj_t *socket, + const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { + // Auto-bind the socket first if the socket is unbound. + if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) { + return -1; + } + + int ret = nina_socket_sendto(socket->fileno, buf, len, ip, port, socket->timeout); + if (ret == NINA_ERROR_TIMEOUT) { + // The socket is Not closed on timeout when calling functions that accept a timeout. + *_errno = MP_ETIMEDOUT; + return -1; + } else if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return ret; +} + +STATIC mp_uint_t network_ninaw10_socket_recvfrom(mod_network_socket_obj_t *socket, + byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { + int ret = 0; + if (socket->type == MOD_NETWORK_SOCK_STREAM) { + *port = 0; + *((uint32_t *)ip) = 0; + ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout); + } else { + // Auto-bind the socket first if the socket is unbound. + if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) { + return -1; + } + ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, (uint16_t *)port, socket->timeout); + } + if (ret == NINA_ERROR_TIMEOUT) { + // The socket is Not closed on timeout when calling functions that accept a timeout. + *_errno = MP_ETIMEDOUT; + return -1; + } else if (ret < 0) { + // Close the socket on any other errors. + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return ret; +} + +STATIC int network_ninaw10_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t + level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { + int ret = nina_socket_setsockopt(socket->fileno, level, opt, optval, optlen); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return 0; +} + +STATIC int network_ninaw10_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) { + if (timeout_ms == UINT32_MAX) { + // no timeout is given, set the socket to blocking mode. + timeout_ms = 0; + } + socket->timeout = timeout_ms; + return 0; +} + +STATIC int network_ninaw10_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) { + *_errno = MP_EIO; + return -1; +} + +static const mp_rom_map_elem_t nina_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_ninaw10_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_ninaw10_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_ninaw10_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&network_ninaw10_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_ninaw10_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_ninaw10_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_ninaw10_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_ninaw10_status_obj) }, + + // Network is not secured. + { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(NINA_SEC_OPEN) }, + // Security type WEP (40 or 104). + { MP_ROM_QSTR(MP_QSTR_WEP), MP_ROM_INT(NINA_SEC_WEP) }, + // Network secured with WPA/WPA2 personal(PSK). + { MP_ROM_QSTR(MP_QSTR_WPA_PSK), MP_ROM_INT(NINA_SEC_WPA_PSK) }, +}; + +static MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table); + +const mod_network_nic_type_t mod_network_nic_type_nina = { + .base = { + { &mp_type_type }, + .name = MP_QSTR_nina, + .make_new = network_ninaw10_make_new, + .locals_dict = (mp_obj_t)&nina_locals_dict, + }, + .gethostbyname = network_ninaw10_gethostbyname, + .socket = network_ninaw10_socket_socket, + .close = network_ninaw10_socket_close, + .bind = network_ninaw10_socket_bind, + .listen = network_ninaw10_socket_listen, + .accept = network_ninaw10_socket_accept, + .connect = network_ninaw10_socket_connect, + .send = network_ninaw10_socket_send, + .recv = network_ninaw10_socket_recv, + .sendto = network_ninaw10_socket_sendto, + .recvfrom = network_ninaw10_socket_recvfrom, + .setsockopt = network_ninaw10_socket_setsockopt, + .settimeout = network_ninaw10_socket_settimeout, + .ioctl = network_ninaw10_socket_ioctl, +}; + +#endif // #if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10 diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index e4b4cb68a..fce99bcdf 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -138,9 +138,9 @@ STATIC int ble_gattc_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_e #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING // Bonding store. -STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, union ble_store_value *value); -STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val); -STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key); +STATIC int ble_secret_store_read(int obj_type, const union ble_store_key *key, union ble_store_value *value); +STATIC int ble_secret_store_write(int obj_type, const union ble_store_value *val); +STATIC int ble_secret_store_delete(int obj_type, const union ble_store_key *key); #endif STATIC int ble_hs_err_to_errno(int err) { @@ -604,6 +604,12 @@ int mp_bluetooth_init(void) { ble_hs_cfg.gatts_register_cb = gatts_register_cb; ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING + ble_hs_cfg.store_read_cb = ble_secret_store_read; + ble_hs_cfg.store_write_cb = ble_secret_store_write; + ble_hs_cfg.store_delete_cb = ble_secret_store_delete; + #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING + MP_STATE_PORT(bluetooth_nimble_root_pointers) = m_new0(mp_bluetooth_nimble_root_pointers_t, 1); mp_bluetooth_gatts_db_create(&MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db); @@ -1202,7 +1208,7 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) { return commmon_gap_event_cb(event, arg); } -int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) { +int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us) { DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n"); if (!mp_bluetooth_is_active()) { return ERRNO_BLUETOOTH_NOT_ACTIVE; @@ -1211,12 +1217,14 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, 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 = { + uint16_t conn_interval_min = min_conn_interval_us ? min_conn_interval_us / BLE_HCI_CONN_ITVL : BLE_GAP_INITIAL_CONN_ITVL_MIN; + uint16_t conn_interval_max = max_conn_interval_us ? max_conn_interval_us / BLE_HCI_CONN_ITVL : BLE_GAP_INITIAL_CONN_ITVL_MAX; + + 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, + .itvl_min = conn_interval_min, + .itvl_max = conn_interval_max, .latency = BLE_GAP_INITIAL_CONN_LATENCY, .supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT, .min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN, @@ -1228,6 +1236,15 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, return ble_hs_err_to_errno(err); } +int mp_bluetooth_gap_peripheral_connect_cancel(void) { + DEBUG_printf("mp_bluetooth_gap_peripheral_connect_cancel\n"); + if (!mp_bluetooth_is_active()) { + return ERRNO_BLUETOOTH_NOT_ACTIVE; + } + int err = ble_gap_conn_cancel(); + return ble_hs_err_to_errno(err); +} + STATIC int ble_gattc_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) { DEBUG_printf("ble_gattc_service_cb: conn_handle=%d status=%d start_handle=%d\n", conn_handle, error->status, service ? service->start_handle : -1); if (!mp_bluetooth_is_active()) { @@ -1739,12 +1756,6 @@ int mp_bluetooth_l2cap_send(uint16_t conn_handle, uint16_t cid, const uint8_t *b *stalled = true; } - // Sometimes we see what looks like BLE_HS_EAGAIN (but it's actually - // OS_ENOMEM in disguise). Fixed in NimBLE v1.4. - if (err == OS_ENOMEM) { - err = BLE_HS_ENOMEM; - } - // Other error codes such as BLE_HS_EBUSY (we're stalled) or BLE_HS_EBADDATA (bigger than MTU). return ble_hs_err_to_errno(err); } @@ -1824,8 +1835,8 @@ int mp_bluetooth_hci_cmd(uint16_t ogf, uint16_t ocf, const uint8_t *req, size_t #if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING -STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, union ble_store_value *value) { - DEBUG_printf("ble_store_ram_read: %d\n", obj_type); +STATIC int ble_secret_store_read(int obj_type, const union ble_store_key *key, union ble_store_value *value) { + DEBUG_printf("ble_secret_store_read: %d\n", obj_type); const uint8_t *key_data; size_t key_data_len; @@ -1859,7 +1870,7 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio } case BLE_STORE_OBJ_TYPE_CCCD: { // TODO: Implement CCCD persistence. - DEBUG_printf("ble_store_ram_read: CCCD not supported.\n"); + DEBUG_printf("ble_secret_store_read: CCCD not supported.\n"); return -1; } default: @@ -1869,18 +1880,18 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio const uint8_t *value_data; size_t value_data_len; if (!mp_bluetooth_gap_on_get_secret(obj_type, key->sec.idx, key_data, key_data_len, &value_data, &value_data_len)) { - DEBUG_printf("ble_store_ram_read: Key not found: type=%d, index=%u, key=0x%p, len=" UINT_FMT "\n", obj_type, key->sec.idx, key_data, key_data_len); + DEBUG_printf("ble_secret_store_read: Key not found: type=%d, index=%u, key=0x%p, len=" UINT_FMT "\n", obj_type, key->sec.idx, key_data, key_data_len); return BLE_HS_ENOENT; } if (value_data_len != sizeof(struct ble_store_value_sec)) { - DEBUG_printf("ble_store_ram_read: Invalid key data: actual=" UINT_FMT " expected=" UINT_FMT "\n", value_data_len, sizeof(struct ble_store_value_sec)); + DEBUG_printf("ble_secret_store_read: Invalid key data: actual=" UINT_FMT " expected=" UINT_FMT "\n", value_data_len, sizeof(struct ble_store_value_sec)); return BLE_HS_ENOENT; } memcpy((uint8_t *)&value->sec, value_data, sizeof(struct ble_store_value_sec)); - DEBUG_printf("ble_store_ram_read: found secret\n"); + DEBUG_printf("ble_secret_store_read: found secret\n"); if (obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC) { // TODO: Verify ediv_rand matches. @@ -1889,8 +1900,8 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio return 0; } -STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) { - DEBUG_printf("ble_store_ram_write: %d\n", obj_type); +STATIC int ble_secret_store_write(int obj_type, const union ble_store_value *val) { + DEBUG_printf("ble_secret_store_write: %d\n", obj_type); switch (obj_type) { case BLE_STORE_OBJ_TYPE_PEER_SEC: case BLE_STORE_OBJ_TYPE_OUR_SEC: { @@ -1908,13 +1919,13 @@ STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) { return BLE_HS_ESTORE_CAP; } - DEBUG_printf("ble_store_ram_write: wrote secret\n"); + DEBUG_printf("ble_secret_store_write: wrote secret\n"); return 0; } case BLE_STORE_OBJ_TYPE_CCCD: { // TODO: Implement CCCD persistence. - DEBUG_printf("ble_store_ram_write: CCCD not supported.\n"); + DEBUG_printf("ble_secret_store_write: CCCD not supported.\n"); // Just pretend we wrote it. return 0; } @@ -1923,8 +1934,8 @@ STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) { } } -STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) { - DEBUG_printf("ble_store_ram_delete: %d\n", obj_type); +STATIC int ble_secret_store_delete(int obj_type, const union ble_store_key *key) { + DEBUG_printf("ble_secret_store_delete: %d\n", obj_type); switch (obj_type) { case BLE_STORE_OBJ_TYPE_PEER_SEC: case BLE_STORE_OBJ_TYPE_OUR_SEC: { @@ -1938,13 +1949,13 @@ STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) { return BLE_HS_ENOENT; } - DEBUG_printf("ble_store_ram_delete: deleted secret\n"); + DEBUG_printf("ble_secret_store_delete: deleted secret\n"); return 0; } case BLE_STORE_OBJ_TYPE_CCCD: { // TODO: Implement CCCD persistence. - DEBUG_printf("ble_store_ram_delete: CCCD not supported.\n"); + DEBUG_printf("ble_secret_store_delete: CCCD not supported.\n"); // Just pretend it wasn't there. return BLE_HS_ENOENT; } @@ -1953,15 +1964,6 @@ STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) { } } -// nimble_port_init always calls ble_store_ram_init. We provide this alternative -// implementation rather than the one in nimble/store/ram/src/ble_store_ram.c. -// TODO: Consider re-implementing nimble_port_init instead. -void ble_store_ram_init(void) { - ble_hs_cfg.store_read_cb = ble_store_ram_read; - ble_hs_cfg.store_write_cb = ble_store_ram_write; - ble_hs_cfg.store_delete_cb = ble_store_ram_delete; -} - #endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING #endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE diff --git a/extmod/nimble/nimble.cmake b/extmod/nimble/nimble.cmake new file mode 100644 index 000000000..3dff1d7d0 --- /dev/null +++ b/extmod/nimble/nimble.cmake @@ -0,0 +1,80 @@ +set(NIMBLE_LIB_DIR "${MICROPY_DIR}/lib/mynewt-nimble") +set(NIMBLE_EXTMOD_DIR "${MICROPY_DIR}/extmod/nimble") + +add_library(micropy_extmod_nimble INTERFACE) + +target_include_directories(micropy_extmod_nimble INTERFACE + ${MICROPY_DIR}/ + ${MICROPY_PORT_DIR}/ + ${NIMBLE_EXTMOD_DIR}/ + ${NIMBLE_LIB_DIR}/ + ${NIMBLE_LIB_DIR}/ext/tinycrypt/include + ${NIMBLE_LIB_DIR}/nimble/host/include + ${NIMBLE_LIB_DIR}/nimble/host/services/gap/include + ${NIMBLE_LIB_DIR}/nimble/host/services/gatt/include + ${NIMBLE_LIB_DIR}/nimble/host/store/ram/include + ${NIMBLE_LIB_DIR}/nimble/host/util/include + ${NIMBLE_LIB_DIR}/nimble/include + ${NIMBLE_LIB_DIR}/nimble/transport/uart/include + ${NIMBLE_LIB_DIR}/porting/nimble/include +) + +target_sources(micropy_extmod_nimble INTERFACE + ${NIMBLE_EXTMOD_DIR}/hal/hal_uart.c + ${NIMBLE_EXTMOD_DIR}/nimble/nimble_npl_os.c + ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/aes_encrypt.c + ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/cmac_mode.c + ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/ecc.c + ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/ecc_dh.c + ${NIMBLE_LIB_DIR}/ext/tinycrypt/src/utils.c + ${NIMBLE_LIB_DIR}/nimble/host/services/gap/src/ble_svc_gap.c + ${NIMBLE_LIB_DIR}/nimble/host/services/gatt/src/ble_svc_gatt.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_att.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_att_clt.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_att_cmd.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_att_svr.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_eddystone.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_gap.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_gattc.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_gatts.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_adv.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_atomic.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_cfg.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_conn.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_flow.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci_cmd.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci_evt.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci_util.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_id.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_log.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_mbuf.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_misc.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_mqueue.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_pvcy.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_startup.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_stop.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_ibeacon.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap_coc.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap_sig.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap_sig_cmd.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_monitor.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_alg.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_cmd.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_lgcy.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_sc.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_store.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_store_util.c + ${NIMBLE_LIB_DIR}/nimble/host/src/ble_uuid.c + ${NIMBLE_LIB_DIR}/nimble/host/util/src/addr.c + ${NIMBLE_LIB_DIR}/nimble/transport/uart/src/ble_hci_uart.c + ${NIMBLE_LIB_DIR}/porting/nimble/src/endian.c + ${NIMBLE_LIB_DIR}/porting/nimble/src/mem.c + ${NIMBLE_LIB_DIR}/porting/nimble/src/nimble_port.c + ${NIMBLE_LIB_DIR}/porting/nimble/src/os_mbuf.c + ${NIMBLE_LIB_DIR}/porting/nimble/src/os_mempool.c + ${NIMBLE_LIB_DIR}/porting/nimble/src/os_msys_init.c +) diff --git a/extmod/nimble/nimble/nimble_npl_os.h b/extmod/nimble/nimble/nimble_npl_os.h index d0803f7e2..3205baa03 100644 --- a/extmod/nimble/nimble/nimble_npl_os.h +++ b/extmod/nimble/nimble/nimble_npl_os.h @@ -35,7 +35,11 @@ // --- Configuration of NimBLE data structures -------------------------------- // This is used at runtime to align allocations correctly. -#define BLE_NPL_OS_ALIGNMENT (sizeof(uintptr_t)) +#if __WORDSIZE == 64 +#define BLE_NPL_OS_ALIGNMENT 8 +#else +#define BLE_NPL_OS_ALIGNMENT 4 +#endif #define BLE_NPL_TIME_FOREVER (0xffffffff) // This is used at compile time to force struct member alignment. See diff --git a/extmod/uasyncio/event.py b/extmod/uasyncio/event.py index c28ad1fb3..1954c80f5 100644 --- a/extmod/uasyncio/event.py +++ b/extmod/uasyncio/event.py @@ -57,6 +57,5 @@ try: yield core._io_queue.queue_read(self) self._flag = 0 - except ImportError: pass diff --git a/extmod/uasyncio/funcs.py b/extmod/uasyncio/funcs.py index 93f4fd256..0ce48b015 100644 --- a/extmod/uasyncio/funcs.py +++ b/extmod/uasyncio/funcs.py @@ -66,7 +66,7 @@ async def gather(*aws, return_exceptions=False): # # cancel all waiting tasks # raise er ts[i] = await ts[i] - except Exception as er: + except (core.CancelledError, Exception) as er: if return_exceptions: ts[i] = er else: diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index f3eac98ce..837c5489b 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -37,6 +37,8 @@ #ifdef _WIN32 #define fsync _commit +#else +#include #endif typedef struct _mp_obj_vfs_posix_file_t { @@ -206,6 +208,32 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ return 0; case MP_STREAM_GET_FILENO: return o->fd; + #if MICROPY_PY_USELECT + case MP_STREAM_POLL: { + #ifdef _WIN32 + mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32")); + #else + mp_uint_t ret = 0; + uint8_t pollevents = 0; + if (arg & MP_STREAM_POLL_RD) { + pollevents |= POLLIN; + } + if (arg & MP_STREAM_POLL_WR) { + pollevents |= POLLOUT; + } + struct pollfd pfd = { .fd = o->fd, .events = pollevents }; + if (poll(&pfd, 1, 0) > 0) { + if (pfd.revents & POLLIN) { + ret |= MP_STREAM_POLL_RD; + } + if (pfd.revents & POLLOUT) { + ret |= MP_STREAM_POLL_WR; + } + } + return ret; + #endif + } + #endif default: *errcode = EINVAL; return MP_STREAM_ERROR; diff --git a/lib/asf4 b/lib/asf4 index d270f79aa..84f56af13 160000 --- a/lib/asf4 +++ b/lib/asf4 @@ -1 +1 @@ -Subproject commit d270f79aa16dd8fd4ae3b6c14544283dcb992e9c +Subproject commit 84f56af13292d8f32c40acbd949bde698ddd4507 diff --git a/lib/lv_bindings b/lib/lv_bindings index 620a3de24..8d890d834 160000 --- a/lib/lv_bindings +++ b/lib/lv_bindings @@ -1 +1 @@ -Subproject commit 620a3de2408d2ccb283c2e710c77c6cf006b42e3 +Subproject commit 8d890d834364548f93c5a56797c427625027d7aa diff --git a/lib/mynewt-nimble b/lib/mynewt-nimble index 97ce3eaca..42849560b 160000 --- a/lib/mynewt-nimble +++ b/lib/mynewt-nimble @@ -1 +1 @@ -Subproject commit 97ce3eacaaa79e8ed6cf71717149ced4f5328ee7 +Subproject commit 42849560ba7906f023f61e5f7ff3709ba2c1dfca diff --git a/lib/pico-sdk b/lib/pico-sdk index bfcbefafc..2062372d2 160000 --- a/lib/pico-sdk +++ b/lib/pico-sdk @@ -1 +1 @@ -Subproject commit bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7 +Subproject commit 2062372d203b372849d573f252cf7c6dc2800c0a diff --git a/lib/stm32lib b/lib/stm32lib index 302c52794..c1b7a4157 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit 302c52794d2f579903f4e49cbad1f5d3a7f401ad +Subproject commit c1b7a415778247dd3881a1f3d11ea02190cbc94d diff --git a/lib/tinyusb b/lib/tinyusb index d49938d0f..4bfab30c0 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit d49938d0f5052bce70e55c652b657c0a6a7e84fe +Subproject commit 4bfab30c02279a0530e1a56f4a7c539f2d35a293 diff --git a/mpy-cross/README.md b/mpy-cross/README.md index bf743a903..83f6d6fd8 100644 --- a/mpy-cross/README.md +++ b/mpy-cross/README.md @@ -17,10 +17,7 @@ by the target MicroPython runtime (eg onto a pyboard's filesystem), and then imported like any other Python module using `import foo`. Different target runtimes may require a different format of the compiled -bytecode, and such options can be passed to the cross compiler. For example, -the unix port of MicroPython requires the following: - - $ ./mpy-cross -mcache-lookup-bc foo.py +bytecode, and such options can be passed to the cross compiler. If the Python code contains `@native` or `@viper` annotations, then you must specify `-march` to match the target architecture. diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 635e53a71..7218921b3 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -108,7 +108,6 @@ STATIC int usage(char **argv) { "Target specific options:\n" "-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, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n" "\n" "Implementation specific options:\n", argv[0] @@ -193,8 +192,6 @@ MP_NOINLINE int main_(int argc, char **argv) { #ifdef _WIN32 set_fmode_binary(); #endif - mp_obj_list_init(mp_sys_path, 0); - mp_obj_list_init(mp_sys_argv, 0); #if MICROPY_EMIT_NATIVE // Set default emitter options @@ -205,7 +202,6 @@ MP_NOINLINE int main_(int argc, char **argv) { // set default compiler configuration 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; @@ -264,10 +260,6 @@ MP_NOINLINE int main_(int argc, char **argv) { return usage(argv); } // TODO check that small_int_bits is within range of host's capabilities - } else if (strcmp(argv[a], "-mno-cache-lookup-bc") == 0) { - mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0; - } else if (strcmp(argv[a], "-mcache-lookup-bc") == 0) { - mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 1; } else if (strcmp(argv[a], "-mno-unicode") == 0) { mp_dynamic_compiler.py_builtins_str_unicode = 0; } else if (strcmp(argv[a], "-municode") == 0) { diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index e7c8edf13..8c716e958 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -57,8 +57,6 @@ #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) #define MICROPY_COMP_RETURN_IF_EXPR (1) -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) - #define MICROPY_READER_POSIX (1) #define MICROPY_ENABLE_RUNTIME (0) #define MICROPY_ENABLE_GC (1) diff --git a/ports/bare-arm/README.md b/ports/bare-arm/README.md index dfa5534d5..37e373e2b 100644 --- a/ports/bare-arm/README.md +++ b/ports/bare-arm/README.md @@ -18,4 +18,4 @@ compiled and executed when the firmware starts. They produce output on the system's stdout. The size of the firmware (the machine code that is programmed to the -microcontroller's flash/ROM) is currently around 57900 bytes. +microcontroller's flash/ROM) is currently around 56500 bytes. diff --git a/ports/bare-arm/mpconfigport.h b/ports/bare-arm/mpconfigport.h index 3bebc3159..65bb67f7b 100644 --- a/ports/bare-arm/mpconfigport.h +++ b/ports/bare-arm/mpconfigport.h @@ -28,38 +28,14 @@ // Options to control how MicroPython is built -// Memory allocation policy -#define MICROPY_QSTR_BYTES_IN_HASH (1) +// Use the minimal starting configuration (disables all optional features). +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_MINIMUM) // Compiler configuration -#define MICROPY_COMP_CONST (0) -#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) +#define MICROPY_ENABLE_COMPILER (1) // Python internal features -#define MICROPY_ENABLE_EXTERNAL_IMPORT (0) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NONE) -#define MICROPY_CPYTHON_COMPAT (0) -#define MICROPY_MODULE_GETATTR (0) -#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) - -// Fine control over Python builtins, classes, modules, etc -#define MICROPY_PY_ASYNC_AWAIT (0) -#define MICROPY_PY_ASSIGN_EXPR (0) -#define MICROPY_PY_BUILTINS_STR_COUNT (0) -#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0) -#define MICROPY_PY_BUILTINS_BYTEARRAY (0) -#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (0) -#define MICROPY_PY_BUILTINS_SET (0) -#define MICROPY_PY_BUILTINS_SLICE (0) -#define MICROPY_PY_BUILTINS_PROPERTY (0) -#define MICROPY_PY_BUILTINS_ENUMERATE (0) -#define MICROPY_PY_BUILTINS_REVERSED (0) -#define MICROPY_PY___FILE__ (0) -#define MICROPY_PY_ARRAY (0) -#define MICROPY_PY_COLLECTIONS (0) -#define MICROPY_PY_IO (0) -#define MICROPY_PY_STRUCT (0) -#define MICROPY_PY_SYS (0) // Type definitions for the specific machine diff --git a/ports/cc3200/boards/WIPY/board.json b/ports/cc3200/boards/WIPY/board.json new file mode 100644 index 000000000..d8293b248 --- /dev/null +++ b/ports/cc3200/boards/WIPY/board.json @@ -0,0 +1,23 @@ +{ + "deploy": [ + "deploy.md" + ], + "docs": "https://docs.pycom.io/datasheets/development/wipy3/", + "features": [ + "BLE", + "Breadboard Friendly", + "MicroSD", + "RGB LED", + "SPI Flash", + "WiFi" + ], + "id": "wipy", + "images": [ + "wipy.jpg" + ], + "mcu": "cc3200", + "product": "WiPy Module", + "thumbnail": "", + "url": "https://pycom.io/product/wipy-3-0/", + "vendor": "Pycom" +} diff --git a/ports/cc3200/boards/WIPY/deploy.md b/ports/cc3200/boards/WIPY/deploy.md new file mode 100644 index 000000000..19dcfc158 --- /dev/null +++ b/ports/cc3200/boards/WIPY/deploy.md @@ -0,0 +1,2 @@ +The following files are firmware for the WiPy. The zip file contains mcuimg.bin +which should be copied via ftp to the /flash/sys directory on the WiPy. diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h index 87689c505..345b64fe4 100644 --- a/ports/cc3200/mpconfigport.h +++ b/ports/cc3200/mpconfigport.h @@ -53,7 +53,6 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) #define MICROPY_OPT_COMPUTED_GOTO (0) -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) #define MICROPY_READER_VFS (1) #ifndef DEBUG // we need ram on the launchxl while debugging #define MICROPY_CPYTHON_COMPAT (1) diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c index b764c4712..81f00e538 100644 --- a/ports/cc3200/mptask.c +++ b/ports/cc3200/mptask.c @@ -99,8 +99,8 @@ OsiTaskHandle svTaskHandle; static fs_user_mount_t *sflash_vfs_fat; static const char fresh_main_py[] = "# main.py -- put your code here!\r\n"; -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" +static const char fresh_boot_py[] = "# boot.py -- run on boot to configure USB and filesystem\r\n" + "# Put app code in main.py\r\n" #if MICROPY_STDIO_UART "import os, machine\r\n" "os.dupterm(machine.UART(0, " MP_STRINGIFY(MICROPY_STDIO_UART_BAUD) "))\r\n" @@ -139,9 +139,6 @@ soft_reset: // MicroPython init mp_init(); - mp_obj_list_init(mp_sys_path, 0); - mp_obj_list_init(mp_sys_argv, 0); - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) // execute all basic initializations mp_irq_init0(); diff --git a/ports/esp32/README.md b/ports/esp32/README.md index c7d40070d..42cd58817 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -75,6 +75,12 @@ $ source export.sh # (or export.bat on Windows) The `install.sh` step only needs to be done once. You will need to source `export.sh` for every new session. +**Note:** If you are building MicroPython for the ESP32-S2, ESP32-C3 or ESP32-S3, +please ensure you are using the following required IDF versions: +- ESP32-S3 currently requires latest `master`, but eventually `v4.4` or later when + it's available. +- ESP32-S2 and ESP32-C3 require `v4.3.1` or later. + Building the firmware --------------------- diff --git a/ports/esp32/boards/ESP32_S2_WROVER/board.json b/ports/esp32/boards/ESP32_S2_WROVER/board.json new file mode 100644 index 000000000..7ebc84415 --- /dev/null +++ b/ports/esp32/boards/ESP32_S2_WROVER/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy_s2.md" + ], + "docs": "", + "features": [ + "BLE", + "SPIRAM", + "WiFi" + ], + "images": [ + "ESP32-S2-WROVER_L_0.jpg" + ], + "mcu": "esp32s2", + "product": "ESP32-S2 WROVER", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake new file mode 100644 index 000000000..806312e5a --- /dev/null +++ b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake @@ -0,0 +1,12 @@ +set(IDF_TARGET esp32s2) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.spiram_sx + boards/sdkconfig.usb + boards/ESP32_S2_WROVER/sdkconfig.board +) + +if(NOT MICROPY_FROZEN_MANIFEST) + set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) +endif() diff --git a/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h new file mode 100644 index 000000000..a96262c60 --- /dev/null +++ b/ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h @@ -0,0 +1,8 @@ +#define MICROPY_HW_BOARD_NAME "ESP32-S2-WROVER" +#define MICROPY_HW_MCU_NAME "ESP32-S2" + +#define MICROPY_PY_BLUETOOTH (0) +#define MICROPY_HW_ENABLE_SDCARD (0) + +#define MICROPY_HW_I2C0_SCL (7) +#define MICROPY_HW_I2C0_SDA (6) diff --git a/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board b/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board new file mode 100644 index 000000000..9373a5223 --- /dev/null +++ b/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board @@ -0,0 +1,11 @@ +CONFIG_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y +CONFIG_ESPTOOLPY_AFTER_NORESET=y + +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_USB_AND_UART=y + +# LWIP +CONFIG_LWIP_LOCAL_HOSTNAME="ESP32-S2-WROVER" +# end of LWIP diff --git a/ports/esp32/boards/GENERIC/board.json b/ports/esp32/boards/GENERIC/board.json new file mode 100644 index 000000000..a52d58007 --- /dev/null +++ b/ports/esp32/boards/GENERIC/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "id": "esp32", + "images": [ + "esp32_devkitc.jpg" + ], + "mcu": "esp32", + "product": "ESP32", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "variants": { + "idf3": "Compiled with IDF 3.x" + }, + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC/board.md b/ports/esp32/boards/GENERIC/board.md new file mode 100644 index 000000000..576ea8045 --- /dev/null +++ b/ports/esp32/boards/GENERIC/board.md @@ -0,0 +1,3 @@ +The following files are daily firmware for ESP32-based boards without external SPIRAM. + +This firmware is compiled using ESP-IDF v4.x. Some older releases are also provided that are compiled with ESP-IDF v3.x. diff --git a/ports/esp32/boards/GENERIC_C3/board.json b/ports/esp32/boards/GENERIC_C3/board.json new file mode 100644 index 000000000..481e66bcc --- /dev/null +++ b/ports/esp32/boards/GENERIC_C3/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "id": "esp32c3", + "images": [ + "esp32c3_devkitmini.jpg" + ], + "mcu": "esp32c3", + "product": "ESP32-C3", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC_C3_USB/board.json b/ports/esp32/boards/GENERIC_C3_USB/board.json new file mode 100644 index 000000000..94d86d442 --- /dev/null +++ b/ports/esp32/boards/GENERIC_C3_USB/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "id": "esp32c3-usb", + "images": [ + "esp32c3_devkitmini.jpg" + ], + "mcu": "esp32c3", + "product": "ESP32-C3 with USB", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC_D2WD/board.json b/ports/esp32/boards/GENERIC_D2WD/board.json new file mode 100644 index 000000000..39fce46bc --- /dev/null +++ b/ports/esp32/boards/GENERIC_D2WD/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "id": "esp32-d2wd", + "images": [ + "generic_d2wd.jpg" + ], + "mcu": "esp32", + "product": "ESP32 D2WD", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board b/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board index 367283ded..07e208a09 100644 --- a/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board +++ b/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board @@ -1,3 +1,7 @@ +# Optimise using -Os to reduce size +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_PERF=n + CONFIG_ESPTOOLPY_FLASHMODE_DIO=y CONFIG_ESPTOOLPY_FLASHFREQ_40M=y CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y diff --git a/ports/esp32/boards/GENERIC_OTA/board.json b/ports/esp32/boards/GENERIC_OTA/board.json new file mode 100644 index 000000000..97756a9fb --- /dev/null +++ b/ports/esp32/boards/GENERIC_OTA/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "id": "esp32-ota", + "images": [ + "esp32_devkitc.jpg" + ], + "mcu": "esp32", + "product": "ESP32 with OTA support", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC_S2/board.json b/ports/esp32/boards/GENERIC_S2/board.json new file mode 100644 index 000000000..dbd3b5b01 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S2/board.json @@ -0,0 +1,18 @@ +{ + "deploy": [ + "../deploy_s2.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "images": [ + "generic_s2.jpg" + ], + "mcu": "esp32s2", + "product": "ESP32-S2", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC_S3/board.json b/ports/esp32/boards/GENERIC_S3/board.json new file mode 100644 index 000000000..058fb7dff --- /dev/null +++ b/ports/esp32/boards/GENERIC_S3/board.json @@ -0,0 +1,18 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "images": [ + "generic_s3.jpg" + ], + "mcu": "esp32s3", + "product": "ESP32-S3", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake new file mode 100644 index 000000000..58b1b25bb --- /dev/null +++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.cmake @@ -0,0 +1,12 @@ +set(IDF_TARGET esp32s3) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.usb + boards/sdkconfig.ble + boards/GENERIC_S3/sdkconfig.board +) + +if(NOT MICROPY_FROZEN_MANIFEST) + set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) +endif() diff --git a/ports/esp32/boards/GENERIC_S3/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h new file mode 100644 index 000000000..3540e5a85 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S3/mpconfigboard.h @@ -0,0 +1,7 @@ +#define MICROPY_HW_BOARD_NAME "ESP32S3 module" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_PY_MACHINE_DAC (0) + +#define MICROPY_HW_I2C0_SCL (9) +#define MICROPY_HW_I2C0_SDA (8) diff --git a/ports/esp32/boards/GENERIC_S3/sdkconfig.board b/ports/esp32/boards/GENERIC_S3/sdkconfig.board new file mode 100644 index 000000000..c9726d423 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S3/sdkconfig.board @@ -0,0 +1,12 @@ +CONFIG_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y +CONFIG_ESPTOOLPY_AFTER_NORESET=y + +CONFIG_SPIRAM_MEMTEST= + +CONFIG_ESPTOOLPY_FLASHSIZE_4MB= +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y +CONFIG_ESPTOOLPY_FLASHSIZE_16MB= +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv" diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json b/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json new file mode 100644 index 000000000..ee2cb8d3f --- /dev/null +++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/board.json @@ -0,0 +1,18 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "WiFi" + ], + "images": [ + "generic_s3.jpg" + ], + "mcu": "esp32s3", + "product": "Generic ESP32-S3 (SPIRAM)", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake new file mode 100644 index 000000000..682c31456 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake @@ -0,0 +1,12 @@ +set(IDF_TARGET esp32s3) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.usb + boards/sdkconfig.spiram_sx + boards/GENERIC_S3_SPIRAM/sdkconfig.board +) + +if(NOT MICROPY_FROZEN_MANIFEST) + set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py) +endif() diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h new file mode 100644 index 000000000..beb796dd9 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h @@ -0,0 +1,8 @@ +#define MICROPY_HW_BOARD_NAME "ESP32S3 module (spiram)" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_PY_BLUETOOTH (0) +#define MICROPY_PY_MACHINE_DAC (0) + +#define MICROPY_HW_I2C0_SCL (9) +#define MICROPY_HW_I2C0_SDA (8) diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board b/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board new file mode 100644 index 000000000..c9726d423 --- /dev/null +++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board @@ -0,0 +1,12 @@ +CONFIG_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y +CONFIG_ESPTOOLPY_AFTER_NORESET=y + +CONFIG_SPIRAM_MEMTEST= + +CONFIG_ESPTOOLPY_FLASHSIZE_4MB= +CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y +CONFIG_ESPTOOLPY_FLASHSIZE_16MB= +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv" diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.json b/ports/esp32/boards/GENERIC_SPIRAM/board.json new file mode 100644 index 000000000..afb57b2ed --- /dev/null +++ b/ports/esp32/boards/GENERIC_SPIRAM/board.json @@ -0,0 +1,23 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "SPIRAM", + "WiFi" + ], + "id": "esp32spiram", + "images": [ + "esp32_psram.jpg" + ], + "mcu": "esp32", + "product": "ESP32 with SPIRAM", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "variants": { + "idf3": "Compiled with IDF 3.x" + }, + "vendor": "Espressif" +} diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.md b/ports/esp32/boards/GENERIC_SPIRAM/board.md new file mode 100644 index 000000000..3b02b902c --- /dev/null +++ b/ports/esp32/boards/GENERIC_SPIRAM/board.md @@ -0,0 +1,3 @@ +The following files are daily firmware for ESP32-based boards with external SPIRAM (also known as PSRAM). + +This firmware is compiled using ESP-IDF v4.x. Some older releases are also provided that are compiled with ESP-IDF v3.x. diff --git a/ports/esp32/boards/LOLIN_S2_MINI/board.json b/ports/esp32/boards/LOLIN_S2_MINI/board.json new file mode 100644 index 000000000..41e62a022 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_MINI/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy_s2.md" + ], + "docs": "", + "features": [ + "SPIRAM", + "USB-C", + "WiFi" + ], + "images": [ + "lolin_s2_mini.jpg" + ], + "mcu": "esp32s2", + "product": "S2 mini", + "thumbnail": "", + "url": "https://www.wemos.cc/en/latest/s2/s2_mini.html", + "vendor": "Wemos" +} diff --git a/ports/esp32/boards/LOLIN_S2_MINI/manifest.py b/ports/esp32/boards/LOLIN_S2_MINI/manifest.py new file mode 100644 index 000000000..f993d4fa6 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_MINI/manifest.py @@ -0,0 +1,2 @@ +include("$(PORT_DIR)/boards/manifest.py") +freeze("./modules") diff --git a/ports/esp32/boards/LOLIN_S2_MINI/modules/s2mini.py b/ports/esp32/boards/LOLIN_S2_MINI/modules/s2mini.py new file mode 100644 index 000000000..4fc038c81 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_MINI/modules/s2mini.py @@ -0,0 +1,31 @@ +# LOLIN S2 MINI MicroPython Helper Library + +from micropython import const +from machine import Pin + +# Pin Assignments + +# SPI +SPI_MOSI = const(11) +SPI_MISO = const(9) +SPI_CLK = const(7) + +# I2C +I2C_SDA = const(33) +I2C_SCL = const(35) + +# DAC +DAC1 = const(17) +DAC2 = const(18) + +# LED +LED = const(15) + +# BUTTON +BUTTON = const(0) + +# Helper methods for built in sensors + +led = Pin(LED, Pin.OUT, value=0) + +button = Pin(BUTTON, Pin.IN, Pin.PULL_UP) diff --git a/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake new file mode 100644 index 000000000..5f157e7e7 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.cmake @@ -0,0 +1,11 @@ +set(IDF_TARGET esp32s2) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.spiram_sx + boards/sdkconfig.usb +) + +if(NOT MICROPY_FROZEN_MANIFEST) + set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) +endif() diff --git a/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h new file mode 100644 index 000000000..e0ef10d1d --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h @@ -0,0 +1,12 @@ +#define MICROPY_HW_BOARD_NAME "LOLIN_S2_MINI" +#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2" + +#define MICROPY_PY_BLUETOOTH (0) +#define MICROPY_HW_ENABLE_SDCARD (0) + +#define MICROPY_HW_I2C0_SCL (35) +#define MICROPY_HW_I2C0_SDA (33) + +#define MICROPY_HW_SPI1_MOSI (11) +#define MICROPY_HW_SPI1_MISO (9) +#define MICROPY_HW_SPI1_SCK (7) diff --git a/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board b/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board new file mode 100644 index 000000000..1a7ef3f8b --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board @@ -0,0 +1,6 @@ +CONFIG_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_USB_AND_UART=y +# LWIP +CONFIG_LWIP_LOCAL_HOSTNAME="LOLIN_S2_MINI" +# end of LWIP diff --git a/ports/esp32/boards/LOLIN_S2_PICO/board.json b/ports/esp32/boards/LOLIN_S2_PICO/board.json new file mode 100644 index 000000000..43322b87b --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_PICO/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy_s2.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly", + "OLED", + "SPIRAM", + "STEMMA QT/QWIIC", + "USB-C", + "WiFi" + ], + "images": [ + "lolin_s2_pico.jpg" + ], + "mcu": "esp32s2", + "product": "S2 pico", + "thumbnail": "", + "url": "https://www.wemos.cc/en/latest/s2/s2_pico.html", + "vendor": "Wemos" +} diff --git a/ports/esp32/boards/LOLIN_S2_PICO/manifest.py b/ports/esp32/boards/LOLIN_S2_PICO/manifest.py new file mode 100644 index 000000000..98d4247c6 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_PICO/manifest.py @@ -0,0 +1,4 @@ +include("$(PORT_DIR)/boards/manifest.py") +freeze("./modules") + +freeze("$(MPY_DIR)/drivers/display", "ssd1306.py") diff --git a/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico.py b/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico.py new file mode 100644 index 000000000..be59db715 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico.py @@ -0,0 +1,38 @@ +# LOLIN S2 PICO MicroPython Helper Library + +from micropython import const +from machine import Pin, I2C, Signal +from s2pico_oled import OLED + +# Pin Assignments + +# SPI +SPI_MOSI = const(35) +SPI_MISO = const(36) +SPI_CLK = const(37) + +# I2C +I2C_SDA = const(8) +I2C_SCL = const(9) + +# DAC +DAC1 = const(17) +DAC2 = const(18) + +# LED +LED = const(10) + +# OLED +OLED_RST = const(18) + +# BUTTON +BUTTON = const(0) + +# Helper methods for built in sensors + +led = Signal(LED, Pin.OUT, value=0, invert=True) + +button = Pin(BUTTON, Pin.IN, Pin.PULL_UP) + +i2c = I2C(0) +oled = OLED(i2c, Pin(OLED_RST)) diff --git a/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico_oled.py b/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico_oled.py new file mode 100644 index 000000000..37dc5a340 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_PICO/modules/s2pico_oled.py @@ -0,0 +1,48 @@ +from time import sleep_ms +from ssd1306 import SSD1306_I2C +import network + + +class OLED(SSD1306_I2C): + def __init__(self, i2c, reset): + reset.init(reset.OUT, value=1) + self._reset = reset + self.reset(False) + super().__init__(128, 32, i2c) + + def reset(self, reinit=True): + self._reset(1) + sleep_ms(1) + self._reset(0) + sleep_ms(10) + self._reset(1) + if reinit: + self.init_display() + + def test(self): + self.fill(0) + self.fill_rect(0, 0, 32, 32, 1) + self.fill_rect(2, 2, 28, 28, 0) + self.vline(9, 8, 22, 1) + self.vline(16, 2, 22, 1) + self.vline(23, 8, 22, 1) + self.fill_rect(26, 24, 2, 4, 1) + self.text("MicroPython", 40, 0, 1) + self.text("SSD1306", 40, 12, 1) + self.text("OLED 128x32", 40, 24, 1) + self.show() + + def display_wifi(self): + self.fill(0) + self.text("Scan...", 0, 0, 1) + self.show() + + sta_if = network.WLAN(network.STA_IF) + sta_if.active(True) + _wifi = sta_if.scan() + + self.fill(0) + self.text(str(len(_wifi)) + " Networks", 0, 0, 1) + self.text(str(_wifi[0][3]) + " " + (_wifi[0][0]).decode("utf-8"), 0, 12, 1) + self.text(str(_wifi[1][3]) + " " + (_wifi[1][0]).decode("utf-8"), 0, 24, 1) + self.show() diff --git a/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake new file mode 100644 index 000000000..5f157e7e7 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.cmake @@ -0,0 +1,11 @@ +set(IDF_TARGET esp32s2) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.spiram_sx + boards/sdkconfig.usb +) + +if(NOT MICROPY_FROZEN_MANIFEST) + set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) +endif() diff --git a/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h new file mode 100644 index 000000000..549dd9847 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h @@ -0,0 +1,12 @@ +#define MICROPY_HW_BOARD_NAME "LOLIN_S2_PICO" +#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2" + +#define MICROPY_PY_BLUETOOTH (0) +#define MICROPY_HW_ENABLE_SDCARD (0) + +#define MICROPY_HW_I2C0_SCL (9) +#define MICROPY_HW_I2C0_SDA (8) + +#define MICROPY_HW_SPI1_MOSI (35) +#define MICROPY_HW_SPI1_MISO (36) +#define MICROPY_HW_SPI1_SCK (37) diff --git a/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board b/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board new file mode 100644 index 000000000..bf0f3e780 --- /dev/null +++ b/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board @@ -0,0 +1,6 @@ +CONFIG_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_USB_AND_UART=y +# LWIP +CONFIG_LWIP_LOCAL_HOSTNAME="LOLIN_S2_PICO" +# end of LWIP diff --git a/ports/esp32/boards/M5STACK_ATOM/board.json b/ports/esp32/boards/M5STACK_ATOM/board.json new file mode 100644 index 000000000..9d1886887 --- /dev/null +++ b/ports/esp32/boards/M5STACK_ATOM/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Grove", + "IMU", + "Infrared", + "RGB LED", + "USB-C", + "WiFi" + ], + "images": [ + "m5stack_atom.jpg" + ], + "mcu": "esp32", + "product": "M5 Stack Atom", + "thumbnail": "", + "url": "https://m5stack.com/", + "vendor": "M5 Stack" +} diff --git a/ports/esp32/boards/SIL_WESP32/board.json b/ports/esp32/boards/SIL_WESP32/board.json new file mode 100644 index 000000000..050620d61 --- /dev/null +++ b/ports/esp32/boards/SIL_WESP32/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "BLE", + "Ethernet", + "PoE", + "WiFi" + ], + "id": "wesp32", + "images": [ + "wesp32-iso.jpg", + "wesp32-top.jpg" + ], + "mcu": "esp32", + "product": "SIL WESP32", + "thumbnail": "", + "url": "https://wesp32.com/", + "vendor": "Silicognition LLC" +} diff --git a/ports/esp32/boards/UM_FEATHERS2/board.json b/ports/esp32/boards/UM_FEATHERS2/board.json new file mode 100644 index 000000000..fa5b213db --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2/board.json @@ -0,0 +1,27 @@ +{ + "deploy": [ + "deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "Feather", + "RGB LED", + "SPIRAM", + "STEMMA QT/QWIIC", + "USB-C", + "WiFi" + ], + "features_non_filterable": [ + "Second LDO" + ], + "id": "featherS2", + "images": [ + "unexpectedmaker_feathers2.jpg" + ], + "mcu": "esp32s2", + "product": "Feather S2", + "thumbnail": "", + "url": "https://feathers2.io/", + "vendor": "Unexpected Maker" +} diff --git a/ports/esp32/boards/UM_FEATHERS2/board.md b/ports/esp32/boards/UM_FEATHERS2/board.md new file mode 100644 index 000000000..e04a8936c --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2/board.md @@ -0,0 +1,2 @@ +The following files are daily firmware for the FeatherS2. This firmware is +compiled using ESP-IDF v4.3 or later. diff --git a/ports/esp32/boards/UM_FEATHERS2/deploy.md b/ports/esp32/boards/UM_FEATHERS2/deploy.md new file mode 100644 index 000000000..24bced3cd --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2/deploy.md @@ -0,0 +1,50 @@ +Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool). + +To flash or erase your FeatherS2, you have to first put it into download mode. +To do this, follow these steps: + +- Press and hold the [BOOT] button +- Press and release the [RESET] button +- Release the [BOOT] button + +Now the board is in download mode and the native USB will have enumerated as a serial device. + +If you are putting MicroPython on your board for the first time then you should +first erase the entire flash using: + +### Linux +```bash +esptool.py --chip esp32s2 --port /dev/ttyACM0 erase_flash +``` + +### Mac +```bash +esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 erase_flash +``` + +### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32s2 --port COM(X) erase_flash +``` + +Now download the version of the firmware you would like to install from the options +below, then use the following command to program the firmware starting at address +0x1000, remembering to replace `feathers2-micropython-firmware-version.bin` with the +name of the firmware you just downloaded: + +### Linux +```bash +esptool.py --chip esp32s2 --port /dev/ttyACM0 write_flash -z 0x1000 feathers2-micropython-firmware-version.bin +``` + +### Mac +```bash +esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 write_flash -z 0x1000 feathers2-micropython-firmware-version.bin +``` + +### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32s2 --port COM(X) write_flash -z 0x1000 feathers2-micropython-firmware-version.bin +``` diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.json b/ports/esp32/boards/UM_FEATHERS2NEO/board.json new file mode 100644 index 000000000..d809485e8 --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.json @@ -0,0 +1,27 @@ +{ + "deploy": [ + "deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "Feather", + "RGB LED", + "SPIRAM", + "STEMMA QT/QWIIC", + "USB-C", + "WiFi" + ], + "features_non_filterable": [ + "5x5 RGB LED Matrix" + ], + "id": "featherS2neo", + "images": [ + "FeatherS2_Neo_White_Product2.jpg" + ], + "mcu": "esp32s2", + "product": "Feather S2 Neo", + "thumbnail": "", + "url": "https://unexpectedmaker.com/feathers2-neo", + "vendor": "Unexpected Maker" +} diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.md b/ports/esp32/boards/UM_FEATHERS2NEO/board.md new file mode 100644 index 000000000..60ee024a1 --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.md @@ -0,0 +1,2 @@ +The following files are daily firmware for the FeatherS2 Neo. This firmware is +compiled using ESP-IDF v4.3 or later. diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/deploy.md b/ports/esp32/boards/UM_FEATHERS2NEO/deploy.md new file mode 100644 index 000000000..b1a116e80 --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2NEO/deploy.md @@ -0,0 +1,50 @@ +Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool). + +To flash or erase your FeatherS2 Neo, you have to first put it into download mode. +To do this, follow these steps: + +- Press and hold the [BOOT] button +- Press and release the [RESET] button +- Release the [BOOT] button + +Now the board is in download mode and the native USB will have enumerated as a serial device. + +If you are putting MicroPython on your board for the first time then you should +first erase the entire flash using: + +### Linux +```bash +esptool.py --chip esp32s2 --port /dev/ttyACM0 erase_flash +``` + +### Mac +```bash +esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 erase_flash +``` + +### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32s2 --port COM(X) erase_flash +``` + +Now download the version of the firmware you would like to install from the options below, +then use the following command to program the firmware starting at address 0x1000, +remembering to replace `feathers2neo-micropython-firmware-version.bin` with the name of +the firmware you just downloaded: + +### Linux +```bash +esptool.py --chip esp32s2 --port /dev/ttyACM0 write_flash -z 0x1000 feathers2neo-micropython-firmware-version.bin +``` + +### Mac +```bash +esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 write_flash -z 0x1000 feathers2neo-micropython-firmware-version.bin +``` + +### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32s2 --port COM(X) write_flash -z 0x1000 feathers2-feathers2neo-firmware-version.bin +``` diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/manifest.py b/ports/esp32/boards/UM_FEATHERS2NEO/manifest.py new file mode 100644 index 000000000..7ae2ed15d --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2NEO/manifest.py @@ -0,0 +1,2 @@ +include("$(PORT_DIR)/boards/manifest.py") +freeze("modules") diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py b/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py new file mode 100644 index 000000000..857c7559d --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py @@ -0,0 +1,90 @@ +# FeatherS2 Neo MicroPython Helper Library +# 2021 Seon Rozenblum - Unexpected Maker +# +# Project home: +# https://unexpectedmaker.com/feathers2-neo +# +# 2021-Sep-04 - v0.1 - Initial implementation + +# Import required libraries +from micropython import const +from machine import Pin, ADC +import machine, time + +# FeatherS2 Neo Hardware Pin Assignments + +# Sense Pins +VBUS_SENSE = const(34) +VBAT_SENSE = const(2) + +# RGB LED Pins +RGB_DATA = const(40) +RGB_PWR = const(39) + +# RGB MATRIX LED Pins +RGB_MATRIX_DATA = const(21) +RGB_MATRIX_PWR = const(4) + +# SPI +SPI_MOSI = const(35) +SPI_MISO = const(37) +SPI_CLK = const(36) + +# I2C +I2C_SDA = const(8) +I2C_SCL = const(9) + +# DAC +DAC1 = const(17) +DAC2 = const(18) + +# Helper functions +def set_pixel_power(state): + """Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep.""" + Pin(RGB_PWR, Pin.OUT).value(state) + + +def set_pixel_matrix_power(state): + """Enable or Disable power to the onboard NeoPixel RGB Matrix to either show colours, or to reduce power for deep sleep.""" + Pin(RGB_MATRIX_PWR, Pin.OUT).value(state) + + +def get_battery_voltage(): + """ + Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage + This is an approximation only, but useful to detect if the charge state of the battery is getting low. + """ + adc = ADC(Pin(VBAT_SENSE)) # Assign the ADC pin to read + measuredvbat = adc.read() # Read the value + measuredvbat /= 8192 # divide by 8192 as we are using the default ADC voltage range of 0-1V + measuredvbat *= 4.2 # Multiply by 4.2V, our reference voltage + return round(measuredvbat, 2) + + +def get_vbus_present(): + """Detect if VBUS (5V) power source is present""" + return Pin(VBUS_SENSE, Pin.IN).value() == 1 + + +# NeoPixel rainbow colour wheel +def rgb_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 RGB LED 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 NeoPixel.""" + set_pixel_power(False) + set_pixel_matrix_power(False) + machine.deepsleep(t) diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake new file mode 100644 index 000000000..b0b3e3aa9 --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake @@ -0,0 +1,8 @@ +set(IDF_TARGET esp32s2) +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.spiram_sx + boards/sdkconfig.usb +) + +set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) \ No newline at end of file diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h new file mode 100644 index 000000000..5ee6874b8 --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h @@ -0,0 +1,12 @@ +#define MICROPY_HW_BOARD_NAME "FeatherS2 Neo" +#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2" + +#define MICROPY_PY_BLUETOOTH (0) +#define MICROPY_HW_ENABLE_SDCARD (0) + +#define MICROPY_HW_I2C0_SCL (9) +#define MICROPY_HW_I2C0_SDA (8) + +#define MICROPY_HW_SPI1_MOSI (35) // SDO +#define MICROPY_HW_SPI1_MISO (37) // SDI +#define MICROPY_HW_SPI1_SCK (36) diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board new file mode 100644 index 000000000..87a92892d --- /dev/null +++ b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board @@ -0,0 +1,8 @@ +CONFIG_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_USB_AND_UART=y +CONFIG_ESPTOOLPY_AFTER_NORESET=y + +# LWIP +CONFIG_LWIP_LOCAL_HOSTNAME="UMFeatherS2Neo" +# end of LWIP diff --git a/ports/esp32/boards/UM_TINYPICO/board.json b/ports/esp32/boards/UM_TINYPICO/board.json new file mode 100644 index 000000000..9f1783a9f --- /dev/null +++ b/ports/esp32/boards/UM_TINYPICO/board.json @@ -0,0 +1,29 @@ +{ + "deploy": [ + "deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "BLE", + "RGB LED", + "SPIRAM", + "USB-C", + "WiFi" + ], + "features_non_filterable": [ + "TinyPICO Compatible" + ], + "id": "tinypico", + "images": [ + "tinypico-v2-both.jpg" + ], + "mcu": "esp32", + "product": "TinyPICO", + "thumbnail": "", + "url": "https://www.tinypico.com/", + "variants": { + "idf3": "Compiled with IDF 3.x" + }, + "vendor": "Unexpected Maker" +} diff --git a/ports/esp32/boards/UM_TINYPICO/board.md b/ports/esp32/boards/UM_TINYPICO/board.md new file mode 100644 index 000000000..d0b1266d2 --- /dev/null +++ b/ports/esp32/boards/UM_TINYPICO/board.md @@ -0,0 +1,3 @@ +The following files are daily firmware for the TinyPICO. This firmware is compiled +using ESP-IDF v4.2 or later. Some older releases are also provided that are +compiled with ESP-IDF v3.x. diff --git a/ports/esp32/boards/UM_TINYPICO/deploy.md b/ports/esp32/boards/UM_TINYPICO/deploy.md new file mode 100644 index 000000000..ed2947867 --- /dev/null +++ b/ports/esp32/boards/UM_TINYPICO/deploy.md @@ -0,0 +1,46 @@ +Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool). + +Your TinyPICO has an auto-reset circuit on it, so there is no need to put it into a +download mode first to erase or flash it. + +If you are putting MicroPython on your board for the first time then you should +first erase the entire flash using: + +### Linux +```bash +esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash +``` + +### Mac +```bash +esptool.py --chip esp32 --port /dev/tty.SLAB_USBtoUART erase_flash +``` + +### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32 --port COM(X) erase_flash +``` + +Now download the version of the firmware you would like to install from the options below, +then use the following command to program the firmware starting at address 0x1000, +remembering to replace `tinypico-micropython-firmware-version.bin` with the name of the +firmware you just downloaded: + +From then on program the firmware starting at address 0x1000: + +### Linux +```bash +esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 912600 write_flash -z 0x1000 tinypico-micropython-firmware-version.bin +``` + +### Mac +```bash +esptool.py --chip esp32 --port /dev/tty.SLAB_USBtoUART --baud 912600 write_flash -z 0x1000 tinypico-micropython-firmware-version.bin +``` + +### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32 --port COM(X) --baud 912600 write_flash -z 0x1000 tinypico-micropython-firmware-version.bin +``` diff --git a/ports/esp32/boards/UM_TINYS2/board.json b/ports/esp32/boards/UM_TINYS2/board.json new file mode 100644 index 000000000..e7068170c --- /dev/null +++ b/ports/esp32/boards/UM_TINYS2/board.json @@ -0,0 +1,26 @@ +{ + "deploy": [ + "deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "RGB LED", + "SPIRAM", + "STEMMA QT/QWIIC", + "USB-C", + "WiFi" + ], + "features_non_filterable": [ + "TinyPICO Compatible" + ], + "id": "tinys2", + "images": [ + "TinyS2+Product+Shot.jpg" + ], + "mcu": "esp32s2", + "product": "Tiny S2", + "thumbnail": "", + "url": "https://unexpectedmaker.com/tinys2", + "vendor": "Unexpected Maker" +} diff --git a/ports/esp32/boards/UM_TINYS2/board.md b/ports/esp32/boards/UM_TINYS2/board.md new file mode 100644 index 000000000..9a61374ed --- /dev/null +++ b/ports/esp32/boards/UM_TINYS2/board.md @@ -0,0 +1,2 @@ +The following files are daily firmware for the TinyS2. This firmware is compiled +using ESP-IDF v4.3 or later. diff --git a/ports/esp32/boards/UM_TINYS2/deploy.md b/ports/esp32/boards/UM_TINYS2/deploy.md new file mode 100644 index 000000000..a46bc9bd1 --- /dev/null +++ b/ports/esp32/boards/UM_TINYS2/deploy.md @@ -0,0 +1,50 @@ +Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool). + +To flash or erase your TinyS2, you have to first put it into download mode. +To do this, follow these steps: + +- Press and hold the [BOOT] button +- Press and release the [RESET] button +- Release the [BOOT] button + +Now the board is in download mode and the native USB will have enumerated as a serial device. + +If you are putting MicroPython on your board for the first time then you should +first erase the entire flash using: + +### Linux +```bash +esptool.py --chip esp32s2 --port /dev/ttyACM0 erase_flash +``` + +### Mac +```bash +esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 erase_flash +``` + +#### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32s2 --port COM(X) erase_flash +``` + +Now download the version of the firmware you would like to install from the options below, +then use the following command to program the firmware starting at address 0x1000, +remembering to replace `tinys2-micropython-firmware-version.bin` with the name of the +firmware you just downloaded: + +#### Linux +```bash +esptool.py --chip esp32s2 --port /dev/ttyACM0 write_flash -z 0x1000 tinys2-micropython-firmware-version.bin +``` + +#### Mac +```bash +esptool.py --chip esp32s2 --port /dev/cu.usbmodem01 write_flash -z 0x1000 tinys2-micropython-firmware-version.bin +``` + +#### Windows +Change (X) to whatever COM port is being used by the board +```bash +esptool --chip esp32s2 --port COM(X) write_flash -z 0x1000 tinys2-micropython-firmware-version.bin +``` diff --git a/ports/esp32/boards/deploy.md b/ports/esp32/boards/deploy.md new file mode 100644 index 000000000..64e683edf --- /dev/null +++ b/ports/esp32/boards/deploy.md @@ -0,0 +1,14 @@ +Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool). + +If you are putting MicroPython on your board for the first time then you should +first erase the entire flash using: + +```bash +esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash +``` + +From then on program the firmware starting at address 0x1000: + +```bash +esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-20190125-v1.10.bin +``` diff --git a/ports/esp32/boards/deploy_s2.md b/ports/esp32/boards/deploy_s2.md new file mode 100644 index 000000000..5b3057087 --- /dev/null +++ b/ports/esp32/boards/deploy_s2.md @@ -0,0 +1,14 @@ +Program your board using the esptool.py program, found [here](https://github.com/espressif/esptool). + +If you are putting MicroPython on your board for the first time then you should +first erase the entire flash using: + +```bash +esptool.py --chip esp32s2 --port /dev/ttyACM0 erase_flash +``` + +From then on program the firmware starting at address 0x1000: + +```bash +esptool.py --chip esp32s2 --port /dev/ttyACM0 write_flash -z 0x1000 board-20210902-v1.17.bin +``` diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index db3455f74..66209aef3 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -3,11 +3,12 @@ CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 -# Compiler options: use -Os to reduce size, but keep full assertions +# Compiler options: use -O2 and disable assertions to improve performance # (CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is for IDF 4.0.2) CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y -CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +CONFIG_COMPILER_OPTIMIZATION_PERF=n +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y # Application manager CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y @@ -62,3 +63,4 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" # To reduce iRAM usage CONFIG_ESP32_WIFI_IRAM_OPT=n CONFIG_ESP32_WIFI_RX_IRAM_OPT=n +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y \ No newline at end of file diff --git a/ports/esp32/boards/sdkconfig.spiram_sx b/ports/esp32/boards/sdkconfig.spiram_sx index 18a0712cb..ef24e9082 100644 --- a/ports/esp32/boards/sdkconfig.spiram_sx +++ b/ports/esp32/boards/sdkconfig.spiram_sx @@ -1,5 +1,7 @@ # MicroPython on ESP32-S2 and ESP32-PAD1_subscript_3, ESP IDF configuration with SPIRAM support CONFIG_ESP32S2_SPIRAM_SUPPORT=y +CONFIG_ESP32S3_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_MODE_QUAD=y CONFIG_SPIRAM_TYPE_AUTO=y CONFIG_DEFAULT_PSRAM_CLK_IO=30 CONFIG_DEFAULT_PSRAM_CS_IO=26 @@ -9,3 +11,5 @@ CONFIG_SPIRAM_BOOT_INIT=y CONFIG_SPIRAM_IGNORE_NOTFOUND=y CONFIG_SPIRAM_USE_MEMMAP=y CONFIG_SPIRAM_MEMTEST=y +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c index 37ecef324..639e0467a 100644 --- a/ports/esp32/esp32_rmt.c +++ b/ports/esp32/esp32_rmt.c @@ -27,6 +27,9 @@ #include "py/runtime.h" #include "modmachine.h" #include "mphalport.h" +#include "modesp32.h" + +#include "esp_task.h" #include "driver/rmt.h" // This exposes the ESP32's RMT module to MicroPython. RMT is provided by the Espressif ESP-IDF: @@ -57,6 +60,38 @@ typedef struct _esp32_rmt_obj_t { bool loop_en; } esp32_rmt_obj_t; +typedef struct _rmt_install_state_t { + SemaphoreHandle_t handle; + uint8_t channel_id; + esp_err_t ret; +} rmt_install_state_t; + +// Current channel used for machine.bitstream, in the machine_bitstream_high_low_rmt +// implementation. A value of -1 means do not use RMT. +int8_t esp32_rmt_bitstream_channel_id = RMT_CHANNEL_MAX - 1; + +STATIC void rmt_install_task(void *pvParameter) { + rmt_install_state_t *state = pvParameter; + state->ret = rmt_driver_install(state->channel_id, 0, 0); + xSemaphoreGive(state->handle); + vTaskDelete(NULL); + for (;;) { + } +} + +// Call rmt_driver_install on core 1. This ensures that the RMT interrupt handler is +// serviced on core 1, so that WiFi (if active) does not interrupt it and cause glitches. +esp_err_t rmt_driver_install_core1(uint8_t channel_id) { + TaskHandle_t th; + rmt_install_state_t state; + state.handle = xSemaphoreCreateBinary(); + state.channel_id = channel_id; + xTaskCreatePinnedToCore(rmt_install_task, "rmt_install_task", 2048 / sizeof(StackType_t), &state, ESP_TASK_PRIO_MIN + 1, &th, 1); + xSemaphoreTake(state.handle, portMAX_DELAY); + vSemaphoreDelete(state.handle); + return state.ret; +} + 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} }, @@ -73,6 +108,10 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz mp_uint_t idle_level = args[3].u_bool; mp_obj_t tx_carrier_obj = args[4].u_obj; + if (esp32_rmt_bitstream_channel_id >= 0 && channel_id == esp32_rmt_bitstream_channel_id) { + mp_raise_ValueError(MP_ERROR_TEXT("channel used by bitstream")); + } + if (clock_div < 1 || clock_div > 255) { mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255")); } @@ -119,7 +158,7 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz config.clk_div = self->clock_div; check_esp_err(rmt_config(&config)); - check_esp_err(rmt_driver_install(config.channel, 0, 0)); + check_esp_err(rmt_driver_install_core1(config.channel)); return MP_OBJ_FROM_PTR(self); } @@ -279,6 +318,27 @@ STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_write_pulses_obj, 2, 3, esp32_rmt_write_pulses); +STATIC mp_obj_t esp32_rmt_bitstream_channel(size_t n_args, const mp_obj_t *args) { + if (n_args > 0) { + if (args[0] == mp_const_none) { + esp32_rmt_bitstream_channel_id = -1; + } else { + mp_int_t channel_id = mp_obj_get_int(args[0]); + if (channel_id < 0 || channel_id >= RMT_CHANNEL_MAX) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid channel")); + } + esp32_rmt_bitstream_channel_id = channel_id; + } + } + if (esp32_rmt_bitstream_channel_id < 0) { + return mp_const_none; + } else { + return MP_OBJ_NEW_SMALL_INT(esp32_rmt_bitstream_channel_id); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_bitstream_channel_fun_obj, 0, 1, esp32_rmt_bitstream_channel); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_rmt_bitstream_channel_obj, MP_ROM_PTR(&esp32_rmt_bitstream_channel_fun_obj)); + 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) }, @@ -287,6 +347,9 @@ STATIC const mp_rom_map_elem_t esp32_rmt_locals_dict_table[] = { { 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 methods + { MP_ROM_QSTR(MP_QSTR_bitstream_channel), MP_ROM_PTR(&esp32_rmt_bitstream_channel_obj) }, }; STATIC MP_DEFINE_CONST_DICT(esp32_rmt_locals_dict, esp32_rmt_locals_dict_table); diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c index 5ac05d56b..6731978e2 100644 --- a/ports/esp32/machine_adc.c +++ b/ports/esp32/machine_adc.c @@ -164,10 +164,14 @@ STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) { case ADC_WIDTH_12Bit: adc_bit_width = 12; break; - #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + #elif CONFIG_IDF_TARGET_ESP32S2 case ADC_WIDTH_BIT_13: adc_bit_width = 13; break; + #elif CONFIG_IDF_TARGET_ESP32S3 + case ADC_WIDTH_BIT_12: + adc_bit_width = 12; + break; #endif default: break; @@ -194,8 +198,10 @@ STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) }, { MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) }, { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) }, - #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + #elif CONFIG_IDF_TARGET_ESP32S2 { MP_ROM_QSTR(MP_QSTR_WIDTH_13BIT), MP_ROM_INT(ADC_WIDTH_BIT_13) }, + #elif CONFIG_IDF_TARGET_ESP32S3 + { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_BIT_12) }, #endif }; diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c index 9d2bb5724..4284b5f8b 100644 --- a/ports/esp32/machine_bitstream.c +++ b/ports/esp32/machine_bitstream.c @@ -24,16 +24,19 @@ * THE SOFTWARE. */ -// This is a translation of the cycle counter implementation in ports/stm32/machine_bitstream.c. - #include "py/mpconfig.h" #include "py/mphal.h" +#include "modesp32.h" #if MICROPY_PY_MACHINE_BITSTREAM +/******************************************************************************/ +// Bit-bang implementation + #define NS_TICKS_OVERHEAD (6) -void IRAM_ATTR machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) { +// This is a translation of the cycle counter implementation in ports/stm32/machine_bitstream.c. +STATIC void IRAM_ATTR machine_bitstream_high_low_bitbang(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) { uint32_t pin_mask, gpio_reg_set, gpio_reg_clear; #if !CONFIG_IDF_TARGET_ESP32C3 if (pin >= 32) { @@ -83,4 +86,125 @@ void IRAM_ATTR machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing mp_hal_quiet_timing_exit(irq_state); } +/******************************************************************************/ +// RMT implementation + +#include "driver/rmt.h" + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0) +// This convenience macro was not available in earlier IDF versions. +#define RMT_DEFAULT_CONFIG_TX(gpio, channel_id) \ + { \ + .rmt_mode = RMT_MODE_TX, \ + .channel = channel_id, \ + .clk_div = 80, \ + .gpio_num = gpio, \ + .mem_block_num = 1, \ + .tx_config = { \ + .loop_en = false, \ + .carrier_freq_hz = 38000, \ + .carrier_duty_percent = 33, \ + .carrier_level = RMT_CARRIER_LEVEL_HIGH, \ + .carrier_en = false, \ + .idle_level = RMT_IDLE_LEVEL_LOW, \ + .idle_output_en = true, \ + } \ + } +#endif + +// Logical 0 and 1 values (encoded as a rmt_item32_t). +// The duration fields will be set later. +STATIC rmt_item32_t bitstream_high_low_0 = {{{ 0, 1, 0, 0 }}}; +STATIC rmt_item32_t bitstream_high_low_1 = {{{ 0, 1, 0, 0 }}}; + +// See https://github.com/espressif/esp-idf/blob/master/examples/common_components/led_strip/led_strip_rmt_ws2812.c +// This is called automatically by the IDF during rmt_write_sample in order to +// convert the byte stream to rmt_item32_t's. +STATIC void IRAM_ATTR bitstream_high_low_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size, size_t wanted_num, size_t *translated_size, size_t *item_num) { + if (src == NULL || dest == NULL) { + *translated_size = 0; + *item_num = 0; + return; + } + + size_t size = 0; + size_t num = 0; + uint8_t *psrc = (uint8_t *)src; + rmt_item32_t *pdest = dest; + while (size < src_size && num < wanted_num) { + for (int i = 0; i < 8; i++) { + // MSB first + if (*psrc & (1 << (7 - i))) { + pdest->val = bitstream_high_low_1.val; + } else { + pdest->val = bitstream_high_low_0.val; + } + num++; + pdest++; + } + size++; + psrc++; + } + + *translated_size = size; + *item_num = num; +} + +// Use the reserved RMT channel to stream high/low data on the specified pin. +STATIC void machine_bitstream_high_low_rmt(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len, uint8_t channel_id) { + rmt_config_t config = RMT_DEFAULT_CONFIG_TX(pin, channel_id); + + // Use 40MHz clock (although 2MHz would probably be sufficient). + config.clk_div = 2; + + // Install the driver on this channel & pin. + check_esp_err(rmt_config(&config)); + check_esp_err(rmt_driver_install_core1(config.channel)); + + // Get the tick rate in kHz (this will likely be 40000). + uint32_t counter_clk_khz = 0; + #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0) + uint8_t div_cnt; + check_esp_err(rmt_get_clk_div(config.channel, &div_cnt)); + counter_clk_khz = APB_CLK_FREQ / div_cnt; + #else + check_esp_err(rmt_get_counter_clock(config.channel, &counter_clk_khz)); + #endif + + counter_clk_khz /= 1000; + + // Convert nanoseconds to pulse duration. + bitstream_high_low_0.duration0 = (counter_clk_khz * timing_ns[0]) / 1e6; + bitstream_high_low_0.duration1 = (counter_clk_khz * timing_ns[1]) / 1e6; + bitstream_high_low_1.duration0 = (counter_clk_khz * timing_ns[2]) / 1e6; + bitstream_high_low_1.duration1 = (counter_clk_khz * timing_ns[3]) / 1e6; + + // Install the bits->highlow translator. + rmt_translator_init(config.channel, bitstream_high_low_rmt_adapter); + + // Stream the byte data using the translator. + check_esp_err(rmt_write_sample(config.channel, buf, len, true)); + + // Wait 50% longer than we expect (if every bit takes the maximum time). + uint32_t timeout_ms = (3 * len / 2) * (1 + (8 * MAX(timing_ns[0] + timing_ns[1], timing_ns[2] + timing_ns[3])) / 1000); + check_esp_err(rmt_wait_tx_done(config.channel, pdMS_TO_TICKS(timeout_ms))); + + // Uninstall the driver. + check_esp_err(rmt_driver_uninstall(config.channel)); + + // Cancel RMT output to GPIO pin. + gpio_matrix_out(pin, SIG_GPIO_OUT_IDX, false, false); +} + +/******************************************************************************/ +// Interface to machine.bitstream + +void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) { + if (esp32_rmt_bitstream_channel_id < 0) { + machine_bitstream_high_low_bitbang(pin, timing_ns, buf, len); + } else { + machine_bitstream_high_low_rmt(pin, timing_ns, buf, len, esp32_rmt_bitstream_channel_id); + } +} + #endif // MICROPY_PY_MACHINE_BITSTREAM diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index ca530ba94..1515b0074 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -36,18 +36,47 @@ #include "driver/spi_master.h" -// Default pins for SPI(1), can be overridden by a board +// SPI mappings by device, naming used by IDF old/new +// upython | ESP32 | ESP32S2 | ESP32S3 | ESP32C3 +// ----------+-----------+-----------+---------+--------- +// SPI(id=1) | HSPI/SPI2 | FSPI/SPI2 | SPI2 | SPI2 +// SPI(id=2) | VSPI/SPI3 | HSPI/SPI3 | SPI3 | err + +// Default pins for SPI(id=1) aka IDF SPI2, can be overridden by a board #ifndef MICROPY_HW_SPI1_SCK -#define MICROPY_HW_SPI1_SCK (14) -#define MICROPY_HW_SPI1_MOSI (13) -#define MICROPY_HW_SPI1_MISO (12) +#ifdef SPI2_IOMUX_PIN_NUM_CLK +// Use IO_MUX pins by default. +// If SPI lines are routed to other pins through GPIO matrix +// routing adds some delay and lower limit applies to SPI clk freq +#define MICROPY_HW_SPI1_SCK SPI2_IOMUX_PIN_NUM_CLK // pin 14 on ESP32 +#define MICROPY_HW_SPI1_MOSI SPI2_IOMUX_PIN_NUM_MOSI // pin 13 on ESP32 +#define MICROPY_HW_SPI1_MISO SPI2_IOMUX_PIN_NUM_MISO // pin 12 on ESP32 +// Only for compatibility with IDF 4.2 and older +#elif CONFIG_IDF_TARGET_ESP32S2 +#define MICROPY_HW_SPI1_SCK FSPI_IOMUX_PIN_NUM_CLK +#define MICROPY_HW_SPI1_MOSI FSPI_IOMUX_PIN_NUM_MOSI +#define MICROPY_HW_SPI1_MISO FSPI_IOMUX_PIN_NUM_MISO +#else +#define MICROPY_HW_SPI1_SCK HSPI_IOMUX_PIN_NUM_CLK +#define MICROPY_HW_SPI1_MOSI HSPI_IOMUX_PIN_NUM_MOSI +#define MICROPY_HW_SPI1_MISO HSPI_IOMUX_PIN_NUM_MISO +#endif #endif -// Default pins for SPI(2), can be overridden by a board +// Default pins for SPI(id=2) aka IDF SPI3, can be overridden by a board #ifndef MICROPY_HW_SPI2_SCK -#define MICROPY_HW_SPI2_SCK (18) -#define MICROPY_HW_SPI2_MOSI (23) -#define MICROPY_HW_SPI2_MISO (19) +#if CONFIG_IDF_TARGET_ESP32 +// ESP32 has IO_MUX pins for VSPI/SPI3 lines, use them as defaults +#define MICROPY_HW_SPI2_SCK VSPI_IOMUX_PIN_NUM_CLK // pin 18 +#define MICROPY_HW_SPI2_MOSI VSPI_IOMUX_PIN_NUM_MOSI // pin 23 +#define MICROPY_HW_SPI2_MISO VSPI_IOMUX_PIN_NUM_MISO // pin 19 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +// ESP32S2 and S3 uses GPIO matrix for SPI3 pins, no IO_MUX possible +// Set defaults to the pins used by SPI2 in Octal mode +#define MICROPY_HW_SPI2_SCK (36) +#define MICROPY_HW_SPI2_MOSI (35) +#define MICROPY_HW_SPI2_MISO (37) +#endif #endif #define MP_HW_SPI_MAX_XFER_BYTES (4092) @@ -55,6 +84,9 @@ #if CONFIG_IDF_TARGET_ESP32C3 #define HSPI_HOST SPI2_HOST +#elif CONFIG_IDF_TARGET_ESP32S3 +#define HSPI_HOST SPI3_HOST +#define FSPI_HOST SPI2_HOST #endif typedef struct _machine_hw_spi_default_pins_t { @@ -85,7 +117,9 @@ typedef struct _machine_hw_spi_obj_t { // Default pin mappings for the hardware SPI instances STATIC const machine_hw_spi_default_pins_t machine_hw_spi_default_pins[2] = { { .sck = MICROPY_HW_SPI1_SCK, .mosi = MICROPY_HW_SPI1_MOSI, .miso = MICROPY_HW_SPI1_MISO }, + #ifdef MICROPY_HW_SPI2_SCK { .sck = MICROPY_HW_SPI2_SCK, .mosi = MICROPY_HW_SPI2_MOSI, .miso = MICROPY_HW_SPI2_MISO }, + #endif }; // Static objects mapping to HSPI and VSPI hardware peripherals @@ -193,6 +227,9 @@ STATIC void machine_hw_spi_init_internal( } if (self->host != HSPI_HOST + #ifdef FSPI_HOST + && self->host != FSPI_HOST + #endif #ifdef VSPI_HOST && self->host != VSPI_HOST #endif @@ -231,7 +268,15 @@ STATIC void machine_hw_spi_init_internal( // Select DMA channel based on the hardware SPI host int dma_chan = 0; if (self->host == HSPI_HOST) { + #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + dma_chan = 3; + #else dma_chan = 1; + #endif + #ifdef FSPI_HOST + } else if (self->host == FSPI_HOST) { + dma_chan = 1; + #endif #ifdef VSPI_HOST } else if (self->host == VSPI_HOST) { dma_chan = 2; @@ -444,7 +489,7 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ machine_hw_spi_obj_t *self; const machine_hw_spi_default_pins_t *default_pins; - if (args[ARG_id].u_int == HSPI_HOST) { + if (args[ARG_id].u_int == 1) { // SPI2_HOST which is FSPI_HOST on ESP32Sx, HSPI_HOST on others self = &machine_hw_spi_obj[0]; default_pins = &machine_hw_spi_default_pins[0]; } else { diff --git a/ports/esp32/machine_i2s.c b/ports/esp32/machine_i2s.c index c650a33be..108caf677 100644 --- a/ports/esp32/machine_i2s.c +++ b/ports/esp32/machine_i2s.c @@ -147,11 +147,9 @@ STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYT { 4, 5, 6, 7, 0, 1, 2, 3 }, // Stereo, 32-bits }; -STATIC machine_i2s_obj_t *machine_i2s_obj[I2S_NUM_MAX]; - void machine_i2s_init0() { for (i2s_port_t p = 0; p < I2S_NUM_MAX; p++) { - machine_i2s_obj[p] = NULL; + MP_STATE_PORT(machine_i2s_obj)[p] = NULL; } } @@ -265,13 +263,22 @@ STATIC uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t * delay = portMAX_DELAY; // block until supplied buffer is filled } - // read a chunk of audio samples from DMA memory - check_esp_err(i2s_read( + esp_err_t ret = i2s_read( self->port, self->transform_buffer, num_bytes_requested_from_dma, &num_bytes_received_from_dma, - delay)); + delay); + + // the following is a workaround for a bug in ESP-IDF v4.4 + // https://github.com/espressif/esp-idf/issues/8121 + #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4) + if ((delay != portMAX_DELAY) && (ret == ESP_ERR_TIMEOUT)) { + ret = ESP_OK; + } + #endif + + check_esp_err(ret); // process the transform buffer one frame at a time. // copy selected bytes from the transform buffer into the user supplied appbuf. @@ -326,7 +333,17 @@ STATIC size_t copy_appbuf_to_dma(machine_i2s_obj_t *self, mp_buffer_info_t *appb delay = portMAX_DELAY; // block until supplied buffer is emptied } - check_esp_err(i2s_write(self->port, appbuf->buf, appbuf->len, &num_bytes_written, delay)); + esp_err_t ret = i2s_write(self->port, appbuf->buf, appbuf->len, &num_bytes_written, delay); + + // the following is a workaround for a bug in ESP-IDF v4.4 + // https://github.com/espressif/esp-idf/issues/8121 + #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4) + if ((delay != portMAX_DELAY) && (ret == ESP_ERR_TIMEOUT)) { + ret = ESP_OK; + } + #endif + + check_esp_err(ret); if ((self->io_mode == UASYNCIO) && (num_bytes_written < appbuf->len)) { // Unable to empty the entire app buffer into DMA memory. This indicates all DMA TX buffers are full. @@ -448,6 +465,12 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args, i2s_config.dma_buf_count = get_dma_buf_count(mode, bits, format, self->ibuf); i2s_config.dma_buf_len = DMA_BUF_LEN_IN_I2S_FRAMES; i2s_config.use_apll = false; + i2s_config.tx_desc_auto_clear = true; + i2s_config.fixed_mclk = 0; + #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4) + i2s_config.mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT; + i2s_config.bits_per_chan = 0; + #endif // I2S queue size equals the number of DMA buffers check_esp_err(i2s_driver_install(self->port, &i2s_config, i2s_config.dma_buf_count, &self->i2s_event_queue)); @@ -455,18 +478,26 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args, // apply low-level workaround for bug in some ESP-IDF versions that swap // the left and right channels // https://github.com/espressif/esp-idf/issues/6625 + #if CONFIG_IDF_TARGET_ESP32S3 + REG_SET_BIT(I2S_TX_CONF_REG(self->port), I2S_TX_MSB_SHIFT); + REG_SET_BIT(I2S_TX_CONF_REG(self->port), I2S_RX_MSB_SHIFT); + #else REG_SET_BIT(I2S_CONF_REG(self->port), I2S_TX_MSB_RIGHT); REG_SET_BIT(I2S_CONF_REG(self->port), I2S_RX_MSB_RIGHT); + #endif i2s_pin_config_t pin_config; + #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4) + pin_config.mck_io_num = I2S_PIN_NO_CHANGE; + #endif pin_config.bck_io_num = self->sck; pin_config.ws_io_num = self->ws; if (mode == (I2S_MODE_MASTER | I2S_MODE_RX)) { pin_config.data_in_num = self->sd; - pin_config.data_out_num = -1; + pin_config.data_out_num = I2S_PIN_NO_CHANGE; } else { // TX - pin_config.data_in_num = -1; + pin_config.data_in_num = I2S_PIN_NO_CHANGE; pin_config.data_out_num = self->sd; } @@ -501,13 +532,13 @@ STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_arg } machine_i2s_obj_t *self; - if (machine_i2s_obj[port] == NULL) { + if (MP_STATE_PORT(machine_i2s_obj)[port] == NULL) { self = m_new_obj(machine_i2s_obj_t); - machine_i2s_obj[port] = self; + MP_STATE_PORT(machine_i2s_obj)[port] = self; self->base.type = &machine_i2s_type; self->port = port; } else { - self = machine_i2s_obj[port]; + self = MP_STATE_PORT(machine_i2s_obj)[port]; machine_i2s_deinit(self); } diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index 6c1e96879..c0c7ddb70 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -84,8 +84,13 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = { {{&machine_pin_type}, GPIO_NUM_13}, {{&machine_pin_type}, GPIO_NUM_14}, {{&machine_pin_type}, GPIO_NUM_15}, + #if CONFIG_ESP32_SPIRAM_SUPPORT + {{NULL}, -1}, + {{NULL}, -1}, + #else {{&machine_pin_type}, GPIO_NUM_16}, {{&machine_pin_type}, GPIO_NUM_17}, + #endif {{&machine_pin_type}, GPIO_NUM_18}, {{&machine_pin_type}, GPIO_NUM_19}, {{NULL}, -1}, @@ -172,7 +177,11 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = { {{NULL}, -1}, // 23 not a pin {{NULL}, -1}, // 24 not a pin {{NULL}, -1}, // 25 not a pin - {{NULL}, -1}, // 26 FLASH/PSRAM + #if CONFIG_SPIRAM + {{NULL}, -1}, // 26 PSRAM + #else + {{&machine_pin_type}, GPIO_NUM_26}, + #endif {{NULL}, -1}, // 27 FLASH/PSRAM {{NULL}, -1}, // 28 FLASH/PSRAM {{NULL}, -1}, // 29 FLASH/PSRAM @@ -195,6 +204,13 @@ STATIC const machine_pin_obj_t machine_pin_obj[] = { {{&machine_pin_type}, GPIO_NUM_46}, #endif + + #if CONFIG_IDF_TARGET_ESP32S3 && MICROPY_HW_ESP32S3_EXTENDED_IO + + {{&machine_pin_type}, GPIO_NUM_47}, + {{&machine_pin_type}, GPIO_NUM_48}, + + #endif }; // forward declaration @@ -518,8 +534,13 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = { {{&machine_pin_irq_type}, GPIO_NUM_13}, {{&machine_pin_irq_type}, GPIO_NUM_14}, {{&machine_pin_irq_type}, GPIO_NUM_15}, + #if CONFIG_ESP32_SPIRAM_SUPPORT + {{NULL}, -1}, + {{NULL}, -1}, + #else {{&machine_pin_irq_type}, GPIO_NUM_16}, {{&machine_pin_irq_type}, GPIO_NUM_17}, + #endif {{&machine_pin_irq_type}, GPIO_NUM_18}, {{&machine_pin_irq_type}, GPIO_NUM_19}, {{NULL}, -1}, @@ -601,7 +622,11 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = { {{NULL}, -1}, // 23 not a pin {{NULL}, -1}, // 24 not a pin {{NULL}, -1}, // 25 not a pin - {{NULL}, -1}, // 26 FLASH/PSRAM + #if CONFIG_SPIRAM + {{NULL}, -1}, // 26 PSRAM + #else + {{&machine_pin_irq_type}, GPIO_NUM_26}, + #endif {{NULL}, -1}, // 27 FLASH/PSRAM {{NULL}, -1}, // 28 FLASH/PSRAM {{NULL}, -1}, // 29 FLASH/PSRAM @@ -621,6 +646,14 @@ STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = { {{&machine_pin_irq_type}, GPIO_NUM_43}, {{&machine_pin_irq_type}, GPIO_NUM_44}, {{&machine_pin_irq_type}, GPIO_NUM_45}, + {{&machine_pin_irq_type}, GPIO_NUM_46}, + + #endif + + #if CONFIG_IDF_TARGET_ESP32S3 && MICROPY_HW_ESP32S3_EXTENDED_IO + + {{&machine_pin_irq_type}, GPIO_NUM_47}, + {{&machine_pin_irq_type}, GPIO_NUM_48}, #endif }; diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index a7d7d29df..43d44249d 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -3,7 +3,10 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Damien P. George + * Copyright (c) 2016-2021 Damien P. George + * Copyright (c) 2018 Alan Dragomirecky + * Copyright (c) 2020 Antoine Aubert + * Copyright (c) 2021 Ihor Nehrutsa * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,186 +26,535 @@ * 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/mphal.h" + #include "driver/ledc.h" #include "esp_err.h" -#include "py/nlr.h" -#include "py/runtime.h" -#include "modmachine.h" -#include "mphalport.h" +#define PWM_DBG(...) +// #define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, "\n"); -// Forward dec'l -extern const mp_obj_type_t machine_pwm_type; +// Total number of channels +#define PWM_CHANNEL_MAX (LEDC_SPEED_MODE_MAX * LEDC_CHANNEL_MAX) -typedef struct _esp32_pwm_obj_t { - mp_obj_base_t base; +typedef struct _chan_t { + // Which channel has which GPIO pin assigned? + // (-1 if not assigned) gpio_num_t pin; - uint8_t active; - uint8_t channel; -} esp32_pwm_obj_t; + // Which channel has which timer assigned? + // (-1 if not assigned) + int timer_idx; +} chan_t; -// Which channel has which GPIO pin assigned? -// (-1 if not assigned) -STATIC int chan_gpio[LEDC_CHANNEL_MAX]; +// List of PWM channels +STATIC chan_t chans[PWM_CHANNEL_MAX]; + +// channel_idx is an index (end-to-end sequential numbering) for all channels +// available on the chip and described in chans[] +#define CHANNEL_IDX(mode, channel) (mode * LEDC_CHANNEL_MAX + channel) +#define CHANNEL_IDX_TO_MODE(channel_idx) (channel_idx / LEDC_CHANNEL_MAX) +#define CHANNEL_IDX_TO_CHANNEL(channel_idx) (channel_idx % LEDC_CHANNEL_MAX) + +// Total number of timers +#define PWM_TIMER_MAX (LEDC_SPEED_MODE_MAX * LEDC_TIMER_MAX) + +// List of timer configs +STATIC ledc_timer_config_t timers[PWM_TIMER_MAX]; + +// timer_idx is an index (end-to-end sequential numbering) for all timers +// available on the chip and configured in timers[] +#define TIMER_IDX(mode, timer) (mode * LEDC_TIMER_MAX + timer) +#define TIMER_IDX_TO_MODE(timer_idx) (timer_idx / LEDC_TIMER_MAX) +#define TIMER_IDX_TO_TIMER(timer_idx) (timer_idx % LEDC_TIMER_MAX) // Params for PW operation -// 5khz +// 5khz is default frequency #define PWFREQ (5000) -// High speed mode -#if CONFIG_IDF_TARGET_ESP32 -#define PWMODE (LEDC_HIGH_SPEED_MODE) -#else -#define PWMODE (LEDC_LOW_SPEED_MODE) -#endif + // 10-bit resolution (compatible with esp8266 PWM) #define PWRES (LEDC_TIMER_10_BIT) -// Timer 1 -#define PWTIMER (LEDC_TIMER_1) + +// Maximum duty value on 10-bit resolution +#define MAX_DUTY_U10 ((1 << PWRES) - 1) +// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/ledc.html#supported-range-of-frequency-and-duty-resolutions +// duty() uses 10-bit resolution or less +// duty_u16() and duty_ns() use 16-bit resolution or less + +// Possible highest resolution in device +#if (LEDC_TIMER_BIT_MAX - 1) < LEDC_TIMER_16_BIT +#define HIGHEST_PWM_RES (LEDC_TIMER_BIT_MAX - 1) +#else +#define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT) // 20 bit for ESP32, but 16 bit is used +#endif +// Duty resolution of user interface in `duty_u16()` and `duty_u16` parameter in constructor/initializer +#define UI_RES_16_BIT (16) +// Maximum duty value on highest user interface resolution +#define UI_MAX_DUTY ((1 << UI_RES_16_BIT) - 1) +// How much to shift from the HIGHEST_PWM_RES duty resolution to the user interface duty resolution UI_RES_16_BIT +#define UI_RES_SHIFT (UI_RES_16_BIT - HIGHEST_PWM_RES) // 0 for ESP32, 2 for S2, S3, C3 + +// If the PWM frequency is less than EMPIRIC_FREQ, then LEDC_REF_CLK_HZ(1 MHz) source is used, else LEDC_APB_CLK_HZ(80 MHz) source is used +#define EMPIRIC_FREQ (10) // Hz // Config of timer upon which we run all PWM'ed GPIO pins STATIC bool pwm_inited = false; -STATIC ledc_timer_config_t timer_cfg = { - .duty_resolution = PWRES, - .freq_hz = PWFREQ, - .speed_mode = PWMODE, - .timer_num = PWTIMER -}; + +// MicroPython PWM object struct +typedef struct _machine_pwm_obj_t { + mp_obj_base_t base; + gpio_num_t pin; + bool active; + int mode; + int channel; + int timer; + int duty_x; // PWRES if duty(), HIGHEST_PWM_RES if duty_u16(), -HIGHEST_PWM_RES if duty_ns() + int duty_u10; // stored values from previous duty setters + int duty_u16; // - / - + int duty_ns; // - / - +} machine_pwm_obj_t; + +STATIC bool is_timer_in_use(int current_channel_idx, int timer_idx); +STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty); +STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty); +STATIC void set_duty_ns(machine_pwm_obj_t *self, int ns); STATIC void pwm_init(void) { - // Initial condition: no channels assigned - for (int x = 0; x < LEDC_CHANNEL_MAX; ++x) { - chan_gpio[x] = -1; + for (int i = 0; i < PWM_CHANNEL_MAX; ++i) { + chans[i].pin = -1; + chans[i].timer_idx = -1; } - // Init with default timer params - ledc_timer_config(&timer_cfg); + // Prepare all timers config + // Initial condition: no timers assigned + for (int i = 0; i < PWM_TIMER_MAX; ++i) { + timers[i].duty_resolution = HIGHEST_PWM_RES; + // unset timer is -1 + timers[i].freq_hz = -1; + timers[i].speed_mode = TIMER_IDX_TO_MODE(i); + timers[i].timer_num = TIMER_IDX_TO_TIMER(i); + timers[i].clk_cfg = LEDC_AUTO_CLK; // will reinstall later according to the EMPIRIC_FREQ + } } -STATIC int set_freq(int newval) { - int ores = timer_cfg.duty_resolution; - int oval = timer_cfg.freq_hz; +// Deinit channel and timer if the timer is unused +STATIC void pwm_deinit(int channel_idx) { + // Valid channel? + if ((channel_idx >= 0) && (channel_idx < PWM_CHANNEL_MAX)) { + // Clean up timer if necessary + int timer_idx = chans[channel_idx].timer_idx; + if (timer_idx != -1) { + if (!is_timer_in_use(channel_idx, timer_idx)) { + check_esp_err(ledc_timer_rst(TIMER_IDX_TO_MODE(timer_idx), TIMER_IDX_TO_TIMER(timer_idx))); + // Flag it unused + timers[chans[channel_idx].timer_idx].freq_hz = -1; + } + } - // Find the highest bit resolution for the requested frequency - if (newval <= 0) { - newval = 1; - } - unsigned int res = 0; - for (unsigned int i = LEDC_APB_CLK_HZ / newval; i > 1; i >>= 1, ++res) { - } - if (res == 0) { - res = 1; - } else if (res > PWRES) { - // Limit resolution to PWRES to match units of our duty - res = PWRES; + int pin = chans[channel_idx].pin; + if (pin != -1) { + int mode = CHANNEL_IDX_TO_MODE(channel_idx); + int channel = CHANNEL_IDX_TO_CHANNEL(channel_idx); + // Mark it unused, and tell the hardware to stop routing + check_esp_err(ledc_stop(mode, channel, 0)); + // Disable ledc signal for the pin + // gpio_matrix_out(pin, SIG_GPIO_OUT_IDX, false, false); + if (mode == LEDC_LOW_SPEED_MODE) { + gpio_matrix_out(pin, LEDC_LS_SIG_OUT0_IDX + channel, false, true); + } else { + #if LEDC_SPEED_MODE_MAX > 1 + #if CONFIG_IDF_TARGET_ESP32 + gpio_matrix_out(pin, LEDC_HS_SIG_OUT0_IDX + channel, false, true); + #else + #error Add supported CONFIG_IDF_TARGET_ESP32_xxx + #endif + #endif + } + } + chans[channel_idx].pin = -1; + chans[channel_idx].timer_idx = -1; } +} - // Configure the new resolution and frequency - timer_cfg.duty_resolution = res; - timer_cfg.freq_hz = newval; - if (ledc_timer_config(&timer_cfg) != ESP_OK) { - timer_cfg.duty_resolution = ores; - timer_cfg.freq_hz = oval; - return 0; +// This called from Ctrl-D soft reboot +void machine_pwm_deinit_all(void) { + if (pwm_inited) { + for (int channel_idx = 0; channel_idx < PWM_CHANNEL_MAX; ++channel_idx) { + pwm_deinit(channel_idx); + } + pwm_inited = false; } - return 1; +} + +STATIC void configure_channel(machine_pwm_obj_t *self) { + ledc_channel_config_t cfg = { + .channel = self->channel, + .duty = (1 << (timers[TIMER_IDX(self->mode, self->timer)].duty_resolution)) / 2, + .gpio_num = self->pin, + .intr_type = LEDC_INTR_DISABLE, + .speed_mode = self->mode, + .timer_sel = self->timer, + }; + if (ledc_channel_config(&cfg) != ESP_OK) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("PWM not supported on Pin(%d)"), self->pin); + } +} + +STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_config_t *timer) { + if (freq != timer->freq_hz) { + // Find the highest bit resolution for the requested frequency + unsigned int i = LEDC_APB_CLK_HZ; // 80 MHz + if (freq < EMPIRIC_FREQ) { + i = LEDC_REF_CLK_HZ; // 1 MHz + } + + #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + // original code + i /= freq; + #else + // See https://github.com/espressif/esp-idf/issues/7722 + int divider = (i + freq / 2) / freq; // rounded + if (divider == 0) { + divider = 1; + } + float f = (float)i / divider; // actual frequency + if (f <= 1.0) { + f = 1.0; + } + i = (unsigned int)roundf((float)i / f); + #endif + + unsigned int res = 0; + for (; i > 1; i >>= 1) { + ++res; + } + if (res == 0) { + res = 1; + } else if (res > HIGHEST_PWM_RES) { + // Limit resolution to HIGHEST_PWM_RES to match units of our duty + res = HIGHEST_PWM_RES; + } + + // Configure the new resolution and frequency + unsigned int save_duty_resolution = timer->duty_resolution; + timer->duty_resolution = res; + timer->freq_hz = freq; + timer->clk_cfg = LEDC_USE_APB_CLK; + if (freq < EMPIRIC_FREQ) { + timer->clk_cfg = LEDC_USE_REF_TICK; + } + + // Set frequency + esp_err_t err = ledc_timer_config(timer); + if (err != ESP_OK) { + if (err == ESP_FAIL) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unreachable frequency %d"), freq); + } else { + check_esp_err(err); + } + } + // Reset the timer if low speed + if (self->mode == LEDC_LOW_SPEED_MODE) { + check_esp_err(ledc_timer_rst(self->mode, self->timer)); + } + + // Save the same duty cycle when frequency is changed + if (save_duty_resolution != timer->duty_resolution) { + if (self->duty_x == HIGHEST_PWM_RES) { + set_duty_u16(self, self->duty_u16); + } else if (self->duty_x == PWRES) { + set_duty_u10(self, self->duty_u10); + } else if (self->duty_x == -HIGHEST_PWM_RES) { + set_duty_ns(self, self->duty_ns); + } + } + } +} + +// Calculate the duty parameters based on an ns value +STATIC int ns_to_duty(machine_pwm_obj_t *self, int ns) { + ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)]; + int64_t duty = ((int64_t)ns * UI_MAX_DUTY * timer.freq_hz + 500000000LL) / 1000000000LL; + if ((ns > 0) && (duty == 0)) { + duty = 1; + } else if (duty > UI_MAX_DUTY) { + duty = UI_MAX_DUTY; + } + return duty; +} + +STATIC int duty_to_ns(machine_pwm_obj_t *self, int duty) { + ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)]; + int64_t ns = ((int64_t)duty * 1000000000LL + (int64_t)timer.freq_hz * UI_MAX_DUTY / 2) / ((int64_t)timer.freq_hz * UI_MAX_DUTY); + return ns; +} + +#define get_duty_raw(self) ledc_get_duty(self->mode, self->channel) + +STATIC uint32_t get_duty_u16(machine_pwm_obj_t *self) { + return ledc_get_duty(self->mode, self->channel) << (HIGHEST_PWM_RES + UI_RES_SHIFT - timers[TIMER_IDX(self->mode, self->timer)].duty_resolution); +} + +STATIC uint32_t get_duty_u10(machine_pwm_obj_t *self) { + return get_duty_u16(self) >> (HIGHEST_PWM_RES - PWRES); +} + +STATIC uint32_t get_duty_ns(machine_pwm_obj_t *self) { + return duty_to_ns(self, get_duty_u16(self)); +} + +STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) { + if ((duty < 0) || (duty > UI_MAX_DUTY)) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_u16 must be from 0 to %d"), UI_MAX_DUTY); + } + ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)]; + int channel_duty = duty >> (HIGHEST_PWM_RES + UI_RES_SHIFT - timer.duty_resolution); + int max_duty = (1 << timer.duty_resolution) - 1; + if (channel_duty < 0) { + channel_duty = 0; + } else if (channel_duty > max_duty) { + channel_duty = max_duty; + } + check_esp_err(ledc_set_duty(self->mode, self->channel, channel_duty)); + check_esp_err(ledc_update_duty(self->mode, self->channel)); + + /* + // Bug: Sometimes duty is not set right now. + // Not a bug. It's a feature. The duty is applied at the beginning of the next signal period. + // Bug: It has been experimentally established that the duty is setted during 2 signal periods, but 1 period is expected. + // See https://github.com/espressif/esp-idf/issues/7288 + if (duty != get_duty_u16(self)) { + PWM_DBG("set_duty_u16(%u), get_duty_u16():%u, channel_duty:%d, duty_resolution:%d, freq_hz:%d", duty, get_duty_u16(self), channel_duty, timer.duty_resolution, timer.freq_hz); + ets_delay_us(2 * 1000000 / timer.freq_hz); + if (duty != get_duty_u16(self)) { + PWM_DBG("set_duty_u16(%u), get_duty_u16():%u, channel_duty:%d, duty_resolution:%d, freq_hz:%d", duty, get_duty_u16(self), channel_duty, timer.duty_resolution, timer.freq_hz); + } + } + */ + + self->duty_x = HIGHEST_PWM_RES; + self->duty_u16 = duty; +} + +STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty) { + if ((duty < 0) || (duty > MAX_DUTY_U10)) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty must be from 0 to %u"), MAX_DUTY_U10); + } + set_duty_u16(self, duty << (HIGHEST_PWM_RES + UI_RES_SHIFT - PWRES)); + self->duty_x = PWRES; + self->duty_u10 = duty; +} + +STATIC void set_duty_ns(machine_pwm_obj_t *self, int ns) { + if ((ns < 0) || (ns > duty_to_ns(self, UI_MAX_DUTY))) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_ns must be from 0 to %d ns"), duty_to_ns(self, UI_MAX_DUTY)); + } + set_duty_u16(self, ns_to_duty(self, ns)); + self->duty_x = -HIGHEST_PWM_RES; + self->duty_ns = ns; } /******************************************************************************/ +#define SAME_FREQ_ONLY (true) +#define SAME_FREQ_OR_FREE (false) +#define ANY_MODE (-1) + +// Return timer_idx. Use TIMER_IDX_TO_MODE(timer_idx) and TIMER_IDX_TO_TIMER(timer_idx) to get mode and timer +STATIC int find_timer(unsigned int freq, bool same_freq_only, int mode) { + int free_timer_idx_found = -1; + // Find a free PWM Timer using the same freq + for (int timer_idx = 0; timer_idx < PWM_TIMER_MAX; ++timer_idx) { + if ((mode == ANY_MODE) || (mode == TIMER_IDX_TO_MODE(timer_idx))) { + if (timers[timer_idx].freq_hz == freq) { + // A timer already uses the same freq. Use it now. + return timer_idx; + } + if (!same_freq_only && (free_timer_idx_found == -1) && (timers[timer_idx].freq_hz == -1)) { + free_timer_idx_found = timer_idx; + // Continue to check if a channel with the same freq is in use. + } + } + } + + return free_timer_idx_found; +} + +// Return true if the timer is in use in addition to current channel +STATIC bool is_timer_in_use(int current_channel_idx, int timer_idx) { + for (int i = 0; i < PWM_CHANNEL_MAX; ++i) { + if ((i != current_channel_idx) && (chans[i].timer_idx == timer_idx)) { + return true; + } + } + + return false; +} + +// Find a free PWM channel, also spot if our pin is already mentioned. +// Return channel_idx. Use CHANNEL_IDX_TO_MODE(channel_idx) and CHANNEL_IDX_TO_CHANNEL(channel_idx) to get mode and channel +STATIC int find_channel(int pin, int mode) { + int avail_idx = -1; + int channel_idx; + for (channel_idx = 0; channel_idx < PWM_CHANNEL_MAX; ++channel_idx) { + if ((mode == ANY_MODE) || (mode == CHANNEL_IDX_TO_MODE(channel_idx))) { + if (chans[channel_idx].pin == pin) { + break; + } + if ((avail_idx == -1) && (chans[channel_idx].pin == -1)) { + avail_idx = channel_idx; + } + } + } + if (channel_idx >= PWM_CHANNEL_MAX) { + channel_idx = avail_idx; + } + return channel_idx; +} + +/******************************************************************************/ // MicroPython bindings for PWM -STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "PWM(%u", self->pin); +STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "PWM(Pin(%u)", self->pin); if (self->active) { - mp_printf(print, ", freq=%u, duty=%u", timer_cfg.freq_hz, - ledc_get_duty(PWMODE, self->channel)); + mp_printf(print, ", freq=%u", ledc_get_freq(self->mode, self->timer)); + + if (self->duty_x == PWRES) { + mp_printf(print, ", duty=%d", get_duty_u10(self)); + } else if (self->duty_x == -HIGHEST_PWM_RES) { + mp_printf(print, ", duty_ns=%d", get_duty_ns(self)); + } else { + mp_printf(print, ", duty_u16=%d", get_duty_u16(self)); + } + int resolution = timers[TIMER_IDX(self->mode, self->timer)].duty_resolution; + mp_printf(print, ", resolution=%d", resolution); + + mp_printf(print, ", (duty=%.2f%%, resolution=%.3f%%)", 100.0 * get_duty_raw(self) / (1 << resolution), 100.0 * 1 / (1 << resolution)); // percents + + mp_printf(print, ", mode=%d, channel=%d, timer=%d", self->mode, self->channel, self->timer); } mp_printf(print, ")"); } -STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, +// This called from pwm.init() method +STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_freq, ARG_duty }; + enum { ARG_freq, ARG_duty, ARG_duty_u16, ARG_duty_ns }; static const mp_arg_t allowed_args[] = { { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_duty, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_duty_u16, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_duty_ns, 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); - int channel; - int avail = -1; + int channel_idx = find_channel(self->pin, ANY_MODE); + if (channel_idx == -1) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM channels:%d"), PWM_CHANNEL_MAX); // in all modes + } - // Find a free PWM channel, also spot if our pin is - // already mentioned. - for (channel = 0; channel < LEDC_CHANNEL_MAX; ++channel) { - if (chan_gpio[channel] == self->pin) { - break; + int duty = args[ARG_duty].u_int; + int duty_u16 = args[ARG_duty_u16].u_int; + int duty_ns = args[ARG_duty_ns].u_int; + if (((duty != -1) && (duty_u16 != -1)) || ((duty != -1) && (duty_ns != -1)) || ((duty_u16 != -1) && (duty_ns != -1))) { + mp_raise_ValueError(MP_ERROR_TEXT("only one of parameters 'duty', 'duty_u16' or 'duty_ns' is allowed")); + } + + int freq = args[ARG_freq].u_int; + // Check if freq wasn't passed as an argument + if (freq == -1) { + // Check if already set, otherwise use the default freq. + // It is possible in case: + // pwm = PWM(pin, freq=1000, duty=256) + // pwm = PWM(pin, duty=128) + if (chans[channel_idx].timer_idx != -1) { + freq = timers[chans[channel_idx].timer_idx].freq_hz; } - if ((avail == -1) && (chan_gpio[channel] == -1)) { - avail = channel; + if (freq <= 0) { + freq = PWFREQ; } } - if (channel >= LEDC_CHANNEL_MAX) { - if (avail == -1) { - mp_raise_ValueError(MP_ERROR_TEXT("out of PWM channels")); - } - channel = avail; + if ((freq <= 0) || (freq > 40000000)) { + mp_raise_ValueError(MP_ERROR_TEXT("freqency must be from 1Hz to 40MHz")); } - self->channel = channel; + + int timer_idx; + int current_timer_idx = chans[channel_idx].timer_idx; + bool current_in_use = is_timer_in_use(channel_idx, current_timer_idx); + if (current_in_use) { + timer_idx = find_timer(freq, SAME_FREQ_OR_FREE, CHANNEL_IDX_TO_MODE(channel_idx)); + } else { + timer_idx = chans[channel_idx].timer_idx; + } + + if (timer_idx == -1) { + timer_idx = find_timer(freq, SAME_FREQ_OR_FREE, ANY_MODE); + } + if (timer_idx == -1) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM timers:%d"), PWM_TIMER_MAX); // in all modes + } + + int mode = TIMER_IDX_TO_MODE(timer_idx); + if (CHANNEL_IDX_TO_MODE(channel_idx) != mode) { + // unregister old channel + chans[channel_idx].pin = -1; + chans[channel_idx].timer_idx = -1; + // find new channel + channel_idx = find_channel(self->pin, mode); + if (CHANNEL_IDX_TO_MODE(channel_idx) != mode) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM channels:%d"), PWM_CHANNEL_MAX); // in current mode + } + } + self->mode = mode; + self->timer = TIMER_IDX_TO_TIMER(timer_idx); + self->channel = CHANNEL_IDX_TO_CHANNEL(channel_idx); // New PWM assignment - self->active = 1; - if (chan_gpio[channel] == -1) { - ledc_channel_config_t cfg = { - .channel = channel, - .duty = (1 << timer_cfg.duty_resolution) / 2, - .gpio_num = self->pin, - .intr_type = LEDC_INTR_DISABLE, - .speed_mode = PWMODE, - .timer_sel = PWTIMER, - }; - if (ledc_channel_config(&cfg) != ESP_OK) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("PWM not supported on pin %d"), self->pin); - } - chan_gpio[channel] = self->pin; + if ((chans[channel_idx].pin == -1) || (chans[channel_idx].timer_idx != timer_idx)) { + configure_channel(self); + chans[channel_idx].pin = self->pin; } + chans[channel_idx].timer_idx = timer_idx; + self->active = true; - // Maybe change PWM timer - int tval = args[ARG_freq].u_int; - if (tval != -1) { - if (tval != timer_cfg.freq_hz) { - if (!set_freq(tval)) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval); - } - } - } + // Set timer frequency + set_freq(self, freq, &timers[timer_idx]); // Set duty cycle? - int dval = args[ARG_duty].u_int; - if (dval != -1) { - dval &= ((1 << PWRES) - 1); - dval >>= PWRES - timer_cfg.duty_resolution; - ledc_set_duty(PWMODE, channel, dval); - ledc_update_duty(PWMODE, channel); + if (duty_u16 != -1) { + set_duty_u16(self, duty_u16); + } else if (duty_ns != -1) { + set_duty_ns(self, duty_ns); + } else if (duty != -1) { + set_duty_u10(self, duty); + } else if (self->duty_x == 0) { + set_duty_u10(self, (1 << PWRES) / 2); // 50% } } -STATIC mp_obj_t esp32_pwm_make_new(const mp_obj_type_t *type, +// This called from PWM() constructor +STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + mp_arg_check_num(n_args, n_kw, 1, 2, true); gpio_num_t pin_id = machine_pin_get_id(args[0]); // create PWM object from the given pin - esp32_pwm_obj_t *self = m_new_obj(esp32_pwm_obj_t); + machine_pwm_obj_t *self = m_new_obj(machine_pwm_obj_t); self->base.type = &machine_pwm_type; self->pin = pin_id; - self->active = 0; + self->active = false; + self->mode = -1; self->channel = -1; + self->timer = -1; + self->duty_x = 0; // start the PWM subsystem if it's not already running if (!pwm_inited) { @@ -213,88 +565,96 @@ STATIC mp_obj_t esp32_pwm_make_new(const mp_obj_type_t *type, // start the PWM running for this channel mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - esp32_pwm_init_helper(self, n_args - 1, args + 1, &kw_args); + mp_machine_pwm_init_helper(self, n_args - 1, args + 1, &kw_args); return MP_OBJ_FROM_PTR(self); } -STATIC mp_obj_t esp32_pwm_init(size_t n_args, - const mp_obj_t *args, mp_map_t *kw_args) { - esp32_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(esp32_pwm_init_obj, 1, esp32_pwm_init); - -STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) { - esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); - int chan = self->channel; - - // Valid channel? - if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) { - // Mark it unused, and tell the hardware to stop routing - chan_gpio[chan] = -1; - ledc_stop(PWMODE, chan, 0); - self->active = 0; - self->channel = -1; - gpio_matrix_out(self->pin, SIG_GPIO_OUT_IDX, false, false); - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_pwm_deinit_obj, esp32_pwm_deinit); - -STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) { - if (n_args == 1) { - // get - return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz); - } - - // set - int tval = mp_obj_get_int(args[1]); - if (!set_freq(tval)) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval); - } - return mp_const_none; +// This called from pwm.deinit() method +STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) { + int channel_idx = CHANNEL_IDX(self->mode, self->channel); + pwm_deinit(channel_idx); + self->active = false; + self->mode = -1; + self->channel = -1; + self->timer = -1; + self->duty_x = 0; } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_freq_obj, 1, 2, esp32_pwm_freq); +// Set's and get's methods of PWM class -STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) { - esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); - int duty; +STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(ledc_get_freq(self->mode, self->timer)); +} - if (n_args == 1) { - // get - duty = ledc_get_duty(PWMODE, self->channel); - duty <<= PWRES - timer_cfg.duty_resolution; - return MP_OBJ_NEW_SMALL_INT(duty); +STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) { + if ((freq <= 0) || (freq > 40000000)) { + mp_raise_ValueError(MP_ERROR_TEXT("freqency must be from 1Hz to 40MHz")); + } + if (freq == timers[TIMER_IDX(self->mode, self->timer)].freq_hz) { + return; } - // set - duty = mp_obj_get_int(args[1]); - duty &= ((1 << PWRES) - 1); - duty >>= PWRES - timer_cfg.duty_resolution; - ledc_set_duty(PWMODE, self->channel, duty); - ledc_update_duty(PWMODE, self->channel); + int current_timer_idx = chans[CHANNEL_IDX(self->mode, self->channel)].timer_idx; + bool current_in_use = is_timer_in_use(CHANNEL_IDX(self->mode, self->channel), current_timer_idx); - return mp_const_none; + // Check if an already running timer with the same freq is running + int new_timer_idx = find_timer(freq, SAME_FREQ_ONLY, self->mode); + + // If no existing timer was found, and the current one is in use, then find a new one + if ((new_timer_idx == -1) && current_in_use) { + // Have to find a new timer + new_timer_idx = find_timer(freq, SAME_FREQ_OR_FREE, self->mode); + + if (new_timer_idx == -1) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM timers:%d"), PWM_TIMER_MAX); // in current mode + } + } + + if ((new_timer_idx != -1) && (new_timer_idx != current_timer_idx)) { + // Bind the channel to the new timer + chans[self->channel].timer_idx = new_timer_idx; + + if (ledc_bind_channel_timer(self->mode, self->channel, TIMER_IDX_TO_TIMER(new_timer_idx)) != ESP_OK) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("failed to bind timer to channel")); + } + + if (!current_in_use) { + // Free the old timer + check_esp_err(ledc_timer_rst(self->mode, self->timer)); + // Flag it unused + timers[current_timer_idx].freq_hz = -1; + } + + current_timer_idx = new_timer_idx; + } + self->mode = TIMER_IDX_TO_MODE(current_timer_idx); + self->timer = TIMER_IDX_TO_TIMER(current_timer_idx); + + // Set the frequency + set_freq(self, freq, &timers[current_timer_idx]); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_duty_obj, - 1, 2, esp32_pwm_duty); -STATIC const mp_rom_map_elem_t esp32_pwm_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp32_pwm_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_pwm_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&esp32_pwm_freq_obj) }, - { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&esp32_pwm_duty_obj) }, -}; +STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(get_duty_u10(self)); +} -STATIC MP_DEFINE_CONST_DICT(esp32_pwm_locals_dict, - esp32_pwm_locals_dict_table); +STATIC void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty) { + set_duty_u10(self, duty); +} -const mp_obj_type_t machine_pwm_type = { - { &mp_type_type }, - .name = MP_QSTR_PWM, - .print = esp32_pwm_print, - .make_new = esp32_pwm_make_new, - .locals_dict = (mp_obj_dict_t *)&esp32_pwm_locals_dict, -}; +STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(get_duty_u16(self)); +} + +STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16) { + set_duty_u16(self, duty_u16); +} + +STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(get_duty_ns(self)); +} + +STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns) { + set_duty_ns(self, duty_ns); +} diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c index 3f70311f7..82c2e6cd4 100644 --- a/ports/esp32/machine_sdcard.c +++ b/ports/esp32/machine_sdcard.c @@ -188,7 +188,11 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args } if (is_spi) { + #if CONFIG_IDF_TARGET_ESP32S3 + self->host.slot = slot_num ? SPI3_HOST : SPI2_HOST; + #else self->host.slot = slot_num ? HSPI_HOST : VSPI_HOST; + #endif } DEBUG_printf(" Calling host.init()"); @@ -198,6 +202,20 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args if (is_spi) { // SPI interface + #if CONFIG_IDF_TARGET_ESP32S3 + STATIC const sdspi_slot_config_t slot_defaults[2] = { + { + .gpio_miso = GPIO_NUM_36, + .gpio_mosi = GPIO_NUM_35, + .gpio_sck = GPIO_NUM_37, + .gpio_cs = GPIO_NUM_34, + .gpio_cd = SDSPI_SLOT_NO_CD, + .gpio_wp = SDSPI_SLOT_NO_WP, + .dma_channel = 2 + }, + SDSPI_SLOT_CONFIG_DEFAULT() + }; + #else STATIC const sdspi_slot_config_t slot_defaults[2] = { { .gpio_miso = GPIO_NUM_19, @@ -210,6 +228,7 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args }, SDSPI_SLOT_CONFIG_DEFAULT() }; + #endif DEBUG_printf(" Setting up SPI slot configuration"); sdspi_slot_config_t slot_config = slot_defaults[slot_num]; diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c index 3b1458149..ea8b5965d 100644 --- a/ports/esp32/machine_timer.c +++ b/ports/esp32/machine_timer.c @@ -134,13 +134,25 @@ STATIC void machine_timer_isr(void *self_in) { #if HAVE_TIMER_LL - #if CONFIG_IDF_TARGET_ESP32 + #if CONFIG_IDF_TARGET_ESP32 && ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) device->hw_timer[self->index].update = 1; #else + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) + #if CONFIG_IDF_TARGET_ESP32S3 + device->hw_timer[self->index].update.tn_update = 1; + #else + device->hw_timer[self->index].update.tx_update = 1; + #endif + #else device->hw_timer[self->index].update.update = 1; #endif + #endif timer_ll_clear_intr_status(device, self->index); + #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) timer_ll_set_alarm_enable(device, self->index, self->repeat); + #else + timer_ll_set_alarm_value(device, self->index, self->repeat); + #endif #else diff --git a/ports/esp32/main.c b/ports/esp32/main.c index a8ea8f1b5..a0663937d 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -101,7 +101,7 @@ void mp_task(void *pvParameter) { #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; + void *mp_task_heap = (void *)SOC_EXTRAM_DATA_LOW; switch (esp_spiram_get_chip_size()) { case ESP_SPIRAM_SIZE_16MBITS: mp_task_heap_size = 2 * 1024 * 1024; @@ -120,7 +120,7 @@ void mp_task(void *pvParameter) { // Try to use the entire external SPIRAM directly for the heap size_t mp_task_heap_size; size_t esp_spiram_size = esp_spiram_get_size(); - void *mp_task_heap = (void *)0x3ff80000 - esp_spiram_size; + void *mp_task_heap = (void *)SOC_EXTRAM_DATA_HIGH - esp_spiram_size; if (esp_spiram_size > 0) { mp_task_heap_size = esp_spiram_size; } else { @@ -140,10 +140,7 @@ soft_reset: mp_stack_set_limit(MP_TASK_STACK_SIZE - MP_TASK_STACK_LIMIT_MARGIN); gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size); mp_init(); - mp_obj_list_init(mp_sys_path, 0); - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); - mp_obj_list_init(mp_sys_argv, 0); readline_init0(); // initialise peripherals @@ -193,6 +190,8 @@ soft_reset_exit: mp_hal_stdout_tx_str("MPY: soft reboot\r\n"); // deinitialise peripherals + machine_pwm_deinit_all(); + // TODO: machine_rmt_deinit_all(); machine_pins_deinit(); machine_deinit(); usocket_events_deinit(); @@ -202,12 +201,20 @@ soft_reset_exit: goto soft_reset; } -void app_main(void) { +void boardctrl_startup(void) { 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(); } +} + +void app_main(void) { + // Hook for a board to run code at start up. + // This defaults to initialising NVS. + MICROPY_BOARD_STARTUP(); + + // Create and transfer control to the MicroPython task. xTaskCreatePinnedToCore(mp_task, "mp_task", MP_TASK_STACK_SIZE / sizeof(StackType_t), NULL, MP_TASK_PRIORITY, &mp_main_task_handle, MP_TASK_COREID); } diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index c63e86d6c..36d3985d4 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -62,12 +62,12 @@ set(MICROPY_SOURCE_PORT ${PROJECT_DIR}/machine_dac.c ${PROJECT_DIR}/machine_i2c.c ${PROJECT_DIR}/machine_i2s.c - ${PROJECT_DIR}/machine_pwm.c ${PROJECT_DIR}/machine_uart.c ${PROJECT_DIR}/modmachine.c ${PROJECT_DIR}/modnetwork.c ${PROJECT_DIR}/network_lan.c ${PROJECT_DIR}/network_ppp.c + ${PROJECT_DIR}/network_wlan.c ${PROJECT_DIR}/mpnimbleport.c ${PROJECT_DIR}/modsocket.c ${PROJECT_DIR}/modesp.c @@ -96,6 +96,7 @@ set(MICROPY_SOURCE_QSTR ${MICROPY_SOURCE_LIB} ${MICROPY_SOURCE_PORT} ${LV_SRC} + ${MICROPY_SOURCE_BOARD} ) set(IDF_COMPONENTS @@ -129,16 +130,16 @@ set(IDF_COMPONENTS nghttp ) -if(IDF_VERSION_MINOR GREATER_EQUAL 1) +if(IDF_VERSION_MINOR GREATER_EQUAL 1 OR IDF_VERSION_MAJOR GREATER_EQUAL 5) list(APPEND IDF_COMPONENTS esp_netif) endif() -if(IDF_VERSION_MINOR GREATER_EQUAL 2) +if(IDF_VERSION_MINOR GREATER_EQUAL 2 OR IDF_VERSION_MAJOR GREATER_EQUAL 5) list(APPEND IDF_COMPONENTS esp_system) list(APPEND IDF_COMPONENTS esp_timer) endif() -if(IDF_VERSION_MINOR GREATER_EQUAL 3) +if(IDF_VERSION_MINOR GREATER_EQUAL 3 OR IDF_VERSION_MAJOR GREATER_EQUAL 5) list(APPEND IDF_COMPONENTS esp_hw_support) list(APPEND IDF_COMPONENTS esp_pm) list(APPEND IDF_COMPONENTS hal) @@ -167,6 +168,7 @@ idf_component_register( ${MICROPY_SOURCE_DRIVERS} ${MICROPY_SOURCE_PORT} ${LV_SRC} + ${MICROPY_SOURCE_BOARD} INCLUDE_DIRS ${MICROPY_INC_CORE} ${MICROPY_INC_USERMOD} @@ -213,7 +215,7 @@ foreach(comp ${IDF_COMPONENTS}) micropy_gather_target_properties(__idf_${comp}) endforeach() -if(IDF_VERSION_MINOR GREATER_EQUAL 2) +if(IDF_VERSION_MINOR GREATER_EQUAL 2 OR IDF_VERSION_MAJOR GREATER_EQUAL 5) # These paths cannot currently be found by the IDF_COMPONENTS search loop above, # so add them explicitly. list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/${IDF_TARGET}/include) diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index 18bd62ee4..d76b3a49a 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -26,9 +26,13 @@ #define RTC_LAST_EXT_PIN 39 #define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) +extern int8_t esp32_rmt_bitstream_channel_id; + extern const mp_obj_type_t esp32_nvs_type; extern const mp_obj_type_t esp32_partition_type; extern const mp_obj_type_t esp32_rmt_type; extern const mp_obj_type_t esp32_ulp_type; +esp_err_t rmt_driver_install_core1(uint8_t channel_id); + #endif // MICROPY_INCLUDED_ESP32_MODESP32_H diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 5f94007d4..cca201572 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -53,6 +53,7 @@ #include "extmod/machine_mem.h" #include "extmod/machine_signal.h" #include "extmod/machine_pulse.h" +#include "extmod/machine_pwm.h" #include "extmod/machine_i2c.h" #include "extmod/machine_spi.h" #include "modmachine.h" @@ -90,6 +91,8 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { esp_pm_config_esp32c3_t pm; #elif CONFIG_IDF_TARGET_ESP32S2 esp_pm_config_esp32s2_t pm; + #elif CONFIG_IDF_TARGET_ESP32S3 + esp_pm_config_esp32s3_t pm; #endif pm.max_freq_mhz = freq; pm.min_freq_mhz = freq; diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index 7bf03b0ca..c773f8dbc 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -15,7 +15,6 @@ extern const mp_obj_type_t machine_pin_type; extern const mp_obj_type_t machine_touchpad_type; extern const mp_obj_type_t machine_adc_type; extern const mp_obj_type_t machine_dac_type; -extern const mp_obj_type_t machine_pwm_type; extern const mp_obj_type_t machine_hw_i2c_type; extern const mp_obj_type_t machine_hw_spi_type; extern const mp_obj_type_t machine_i2s_type; @@ -27,6 +26,8 @@ void machine_init(void); void machine_deinit(void); void machine_pins_init(void); void machine_pins_deinit(void); +void machine_pwm_deinit_all(void); +// TODO: void machine_rmt_deinit_all(void); void machine_timer_deinit_all(void); void machine_i2s_init0(); diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 2b64105e7..a16c67eeb 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -31,28 +31,16 @@ * THE SOFTWARE. */ -#include -#include #include -#include "py/nlr.h" -#include "py/objlist.h" #include "py/runtime.h" -#include "py/mphal.h" #include "py/mperrno.h" #include "shared/netutils/netutils.h" -#include "esp_eth.h" +#include "modnetwork.h" + #include "esp_wifi.h" #include "esp_log.h" #include "lwip/dns.h" -#include "mdns.h" - -#if !MICROPY_ESP_IDF_4 -#include "esp_wifi_types.h" -#include "esp_event_loop.h" -#endif - -#include "modnetwork.h" #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0) #define DNS_MAIN TCPIP_ADAPTER_DNS_MAIN @@ -62,7 +50,7 @@ #define MODNETWORK_INCLUDE_CONSTANTS (1) -NORETURN void _esp_exceptions(esp_err_t e) { +NORETURN void esp_exceptions_helper(esp_err_t e) { switch (e) { case ESP_ERR_WIFI_NOT_INIT: mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Initialized")); @@ -107,122 +95,16 @@ NORETURN void _esp_exceptions(esp_err_t e) { } } -static inline void esp_exceptions(esp_err_t e) { - if (e != ESP_OK) { - _esp_exceptions(e); - } -} - -#define ESP_EXCEPTIONS(x) do { esp_exceptions(x); } while (0); - -typedef struct _wlan_if_obj_t { - mp_obj_base_t base; - int if_id; -} wlan_if_obj_t; - -const mp_obj_type_t wlan_if_type; -STATIC const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA}; -STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP}; - -// Set to "true" if esp_wifi_start() was called -static bool wifi_started = false; - -// Set to "true" if the STA interface is requested to be connected by the -// user, used for automatic reassociation. -static bool wifi_sta_connect_requested = false; - -// Set to "true" if the STA interface is connected to wifi and has IP address. -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 - -static uint8_t conf_wifi_sta_reconnects = 0; -static uint8_t wifi_sta_reconnects; - // This function is called by the system-event task and so runs in a different // thread to the main MicroPython task. It must not raise any Python exceptions. static esp_err_t event_handler(void *ctx, system_event_t *event) { switch (event->event_id) { case SYSTEM_EVENT_STA_START: - ESP_LOGI("wifi", "STA_START"); - wifi_sta_reconnects = 0; - break; case SYSTEM_EVENT_STA_CONNECTED: - ESP_LOGI("network", "CONNECTED"); - break; case SYSTEM_EVENT_STA_GOT_IP: - ESP_LOGI("network", "GOT_IP"); - wifi_sta_connected = true; - 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 + case SYSTEM_EVENT_STA_DISCONNECTED: + network_wlan_event_handler(event); break; - case SYSTEM_EVENT_STA_DISCONNECTED: { - // This is a workaround as ESP32 WiFi libs don't currently - // auto-reassociate. - system_event_sta_disconnected_t *disconn = &event->event_info.disconnected; - char *message = ""; - wifi_sta_disconn_reason = disconn->reason; - switch (disconn->reason) { - case WIFI_REASON_BEACON_TIMEOUT: - // AP has dropped out; try to reconnect. - message = "\nbeacon timeout"; - break; - case WIFI_REASON_NO_AP_FOUND: - // AP may not exist, or it may have momentarily dropped out; try to reconnect. - 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"; - break; - default: - // Let other errors through and try to reconnect. - break; - } - ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message); - - wifi_sta_connected = false; - if (wifi_sta_connect_requested) { - wifi_mode_t mode; - if (esp_wifi_get_mode(&mode) != ESP_OK) { - break; - } - if (!(mode & WIFI_MODE_STA)) { - break; - } - if (conf_wifi_sta_reconnects) { - ESP_LOGI("wifi", "reconnect counter=%d, max=%d", - wifi_sta_reconnects, conf_wifi_sta_reconnects); - if (++wifi_sta_reconnects >= conf_wifi_sta_reconnects) { - break; - } - } - esp_err_t e = esp_wifi_connect(); - if (e != ESP_OK) { - ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e); - } - } - break; - } case SYSTEM_EVENT_GOT_IP6: ESP_LOGI("network", "Got IPv6"); break; @@ -248,49 +130,13 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) { return ESP_OK; } -/*void error_check(bool status, const char *msg) { - if (!status) { - mp_raise_msg(&mp_type_OSError, msg); - } -} -*/ - -STATIC void require_if(mp_obj_t wlan_if, int if_no) { - wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if); - if (self->if_id != if_no) { - mp_raise_msg(&mp_type_OSError, if_no == WIFI_IF_STA ? MP_ERROR_TEXT("STA required") : MP_ERROR_TEXT("AP required")); - } -} - -STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { - static int initialized = 0; - if (!initialized) { - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_LOGD("modnetwork", "Initializing WiFi"); - ESP_EXCEPTIONS(esp_wifi_init(&cfg)); - ESP_EXCEPTIONS(esp_wifi_set_storage(WIFI_STORAGE_RAM)); - ESP_LOGD("modnetwork", "Initialized"); - initialized = 1; - } - - int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA; - if (idx == WIFI_IF_STA) { - return MP_OBJ_FROM_PTR(&wlan_sta_obj); - } else if (idx == WIFI_IF_AP) { - return MP_OBJ_FROM_PTR(&wlan_ap_obj); - } else { - mp_raise_ValueError(MP_ERROR_TEXT("invalid WLAN interface identifier")); - } -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan); - STATIC mp_obj_t esp_initialize() { static int initialized = 0; if (!initialized) { ESP_LOGD("modnetwork", "Initializing TCP/IP"); tcpip_adapter_init(); ESP_LOGD("modnetwork", "Initializing Event Loop"); - ESP_EXCEPTIONS(esp_event_loop_init(event_handler, NULL)); + esp_exceptions(esp_event_loop_init(event_handler, NULL)); ESP_LOGD("modnetwork", "esp_event_loop_init done"); initialized = 1; } @@ -298,214 +144,6 @@ STATIC mp_obj_t esp_initialize() { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_initialize_obj, esp_initialize); -#if (WIFI_MODE_STA & WIFI_MODE_AP != WIFI_MODE_NULL || WIFI_MODE_STA | WIFI_MODE_AP != WIFI_MODE_APSTA) -#error WIFI_MODE_STA and WIFI_MODE_AP are supposed to be bitfields! -#endif - -STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) { - wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); - - wifi_mode_t mode; - if (!wifi_started) { - mode = WIFI_MODE_NULL; - } else { - ESP_EXCEPTIONS(esp_wifi_get_mode(&mode)); - } - - int bit = (self->if_id == WIFI_IF_STA) ? WIFI_MODE_STA : WIFI_MODE_AP; - - if (n_args > 1) { - bool active = mp_obj_is_true(args[1]); - mode = active ? (mode | bit) : (mode & ~bit); - if (mode == WIFI_MODE_NULL) { - if (wifi_started) { - ESP_EXCEPTIONS(esp_wifi_stop()); - wifi_started = false; - } - } else { - ESP_EXCEPTIONS(esp_wifi_set_mode(mode)); - if (!wifi_started) { - ESP_EXCEPTIONS(esp_wifi_start()); - wifi_started = true; - } - } - } - - return (mode & bit) ? mp_const_true : mp_const_false; -} - -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active); - -STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_ssid, ARG_password, ARG_bssid }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_bssid, 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 - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - wifi_config_t wifi_sta_config = {0}; - - // configure any parameters that are given - if (n_args > 1) { - 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); - memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); - } - if (args[ARG_password].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_password].u_obj, &len); - memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password))); - } - if (args[ARG_bssid].u_obj != mp_const_none) { - p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len); - if (len != sizeof(wifi_sta_config.sta.bssid)) { - mp_raise_ValueError(NULL); - } - wifi_sta_config.sta.bssid_set = 1; - memcpy(wifi_sta_config.sta.bssid, p, sizeof(wifi_sta_config.sta.bssid)); - } - ESP_EXCEPTIONS(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config)); - } - - wifi_sta_reconnects = 0; - // connect to the WiFi AP - MP_THREAD_GIL_EXIT(); - ESP_EXCEPTIONS(esp_wifi_connect()); - MP_THREAD_GIL_ENTER(); - wifi_sta_connect_requested = true; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_connect_obj, 1, esp_connect); - -STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { - wifi_sta_connect_requested = false; - ESP_EXCEPTIONS(esp_wifi_disconnect()); - return mp_const_none; -} - -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); - -// Cases similar to ESP8266 user_interface.h -// Error cases are referenced from wifi_err_reason_t in ESP-IDF -enum { - STAT_IDLE = 1000, - STAT_CONNECTING = 1001, - STAT_GOT_IP = 1010, -}; - -STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { - wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); - if (n_args == 1) { - if (self->if_id == WIFI_IF_STA) { - // Case of no arg is only for the STA interface - if (wifi_sta_connected) { - // Happy path, connected with IP - return MP_OBJ_NEW_SMALL_INT(STAT_GOT_IP); - } else if (wifi_sta_connect_requested - && (conf_wifi_sta_reconnects == 0 - || wifi_sta_reconnects < conf_wifi_sta_reconnects)) { - // No connection or error, but is requested = Still connecting - return MP_OBJ_NEW_SMALL_INT(STAT_CONNECTING); - } else if (wifi_sta_disconn_reason == 0) { - // No activity, No error = Idle - return MP_OBJ_NEW_SMALL_INT(STAT_IDLE); - } else { - // Simply pass the error through from ESP-identifier - return MP_OBJ_NEW_SMALL_INT(wifi_sta_disconn_reason); - } - } - return mp_const_none; - } - - // one argument: return status based on query parameter - switch ((uintptr_t)args[1]) { - case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): { - // return list of connected stations, only if in soft-AP mode - require_if(args[0], WIFI_IF_AP); - wifi_sta_list_t station_list; - ESP_EXCEPTIONS(esp_wifi_ap_get_sta_list(&station_list)); - wifi_sta_info_t *stations = (wifi_sta_info_t *)station_list.sta; - mp_obj_t list = mp_obj_new_list(0, NULL); - for (int i = 0; i < station_list.num; ++i) { - mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL); - t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac)); - mp_obj_list_append(list, t); - } - return list; - } - 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(MP_ERROR_TEXT("unknown status param")); - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status); - -STATIC mp_obj_t esp_scan(mp_obj_t self_in) { - // check that STA mode is active - wifi_mode_t mode; - ESP_EXCEPTIONS(esp_wifi_get_mode(&mode)); - if ((mode & WIFI_MODE_STA) == 0) { - mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("STA must be active")); - } - - mp_obj_t list = mp_obj_new_list(0, NULL); - wifi_scan_config_t config = { 0 }; - config.show_hidden = true; - MP_THREAD_GIL_EXIT(); - esp_err_t status = esp_wifi_scan_start(&config, 1); - MP_THREAD_GIL_ENTER(); - if (status == 0) { - uint16_t count = 0; - ESP_EXCEPTIONS(esp_wifi_scan_get_ap_num(&count)); - wifi_ap_record_t *wifi_ap_records = calloc(count, sizeof(wifi_ap_record_t)); - ESP_EXCEPTIONS(esp_wifi_scan_get_ap_records(&count, wifi_ap_records)); - for (uint16_t i = 0; i < count; i++) { - mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); - uint8_t *x = memchr(wifi_ap_records[i].ssid, 0, sizeof(wifi_ap_records[i].ssid)); - int ssid_len = x ? x - wifi_ap_records[i].ssid : sizeof(wifi_ap_records[i].ssid); - t->items[0] = mp_obj_new_bytes(wifi_ap_records[i].ssid, ssid_len); - t->items[1] = mp_obj_new_bytes(wifi_ap_records[i].bssid, sizeof(wifi_ap_records[i].bssid)); - t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].primary); - t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].rssi); - t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].authmode); - t->items[5] = mp_const_false; // XXX hidden? - mp_obj_list_append(list, MP_OBJ_FROM_PTR(t)); - } - free(wifi_ap_records); - } - return list; -} - -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan); - -STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) { - wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->if_id == WIFI_IF_STA) { - return mp_obj_new_bool(wifi_sta_connected); - } else { - wifi_sta_list_t sta; - esp_wifi_ap_get_sta_list(&sta); - return mp_obj_new_bool(sta.num != 0); - } -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected); - STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); tcpip_adapter_ip_info_t info; @@ -543,18 +181,18 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { if (self->if_id == WIFI_IF_STA || self->if_id == ESP_IF_ETH) { esp_err_t e = tcpip_adapter_dhcpc_stop(self->if_id); if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) { - _esp_exceptions(e); + esp_exceptions_helper(e); } - ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(self->if_id, &info)); - ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, DNS_MAIN, &dns_info)); + esp_exceptions(tcpip_adapter_set_ip_info(self->if_id, &info)); + esp_exceptions(tcpip_adapter_set_dns_info(self->if_id, DNS_MAIN, &dns_info)); } else if (self->if_id == WIFI_IF_AP) { esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP); if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) { - _esp_exceptions(e); + esp_exceptions_helper(e); } - ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info)); - ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_AP, DNS_MAIN, &dns_info)); - ESP_EXCEPTIONS(tcpip_adapter_dhcps_start(WIFI_IF_AP)); + esp_exceptions(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info)); + esp_exceptions(tcpip_adapter_set_dns_info(WIFI_IF_AP, DNS_MAIN, &dns_info)); + esp_exceptions(tcpip_adapter_dhcps_start(WIFI_IF_AP)); } } else { // check for the correct string @@ -562,222 +200,32 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) { if ((self->if_id != WIFI_IF_STA && self->if_id != ESP_IF_ETH) || strcmp("dhcp", mode)) { mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments")); } - ESP_EXCEPTIONS(tcpip_adapter_dhcpc_start(self->if_id)); + esp_exceptions(tcpip_adapter_dhcpc_start(self->if_id)); } return mp_const_none; } } - MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig); -STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - if (n_args != 1 && kwargs->used != 0) { - mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed")); - } - - wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); - - bool is_wifi = self->if_id == WIFI_IF_AP || self->if_id == WIFI_IF_STA; - - wifi_config_t 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; - - switch ((uintptr_t)kwargs->table[i].key) { - case QS(MP_QSTR_mac): { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ); - if (bufinfo.len != 6) { - mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length")); - } - ESP_EXCEPTIONS(esp_wifi_set_mac(self->if_id, bufinfo.buf)); - break; - } - case QS(MP_QSTR_essid): { - req_if = WIFI_IF_AP; - 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); - cfg.ap.ssid_len = len; - break; - } - case QS(MP_QSTR_hidden): { - req_if = WIFI_IF_AP; - cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value); - break; - } - case QS(MP_QSTR_authmode): { - req_if = WIFI_IF_AP; - cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value); - break; - } - case QS(MP_QSTR_password): { - req_if = WIFI_IF_AP; - 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); - cfg.ap.password[len] = 0; - break; - } - case QS(MP_QSTR_channel): { - req_if = WIFI_IF_AP; - cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); - break; - } - case QS(MP_QSTR_dhcp_hostname): { - const char *s = mp_obj_str_get_str(kwargs->table[i].value); - ESP_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id, s)); - break; - } - case QS(MP_QSTR_max_clients): { - req_if = WIFI_IF_AP; - cfg.ap.max_connection = mp_obj_get_int(kwargs->table[i].value); - break; - } - case QS(MP_QSTR_reconnects): { - int reconnects = mp_obj_get_int(kwargs->table[i].value); - req_if = WIFI_IF_STA; - // parameter reconnects == -1 means to retry forever. - // here means conf_wifi_sta_reconnects == 0 to retry forever. - conf_wifi_sta_reconnects = (reconnects == -1) ? 0 : reconnects + 1; - break; - } - default: - goto unknown; - } - - // We post-check interface requirements to save on code size - if (req_if >= 0) { - require_if(args[0], req_if); - } - } - } - - ESP_EXCEPTIONS(esp_wifi_set_config(self->if_id, &cfg)); - - return mp_const_none; - } - - // Get config - - if (n_args != 2) { - mp_raise_TypeError(MP_ERROR_TEXT("can query only one param")); - } - - int req_if = -1; - mp_obj_t val = mp_const_none; - - switch ((uintptr_t)args[1]) { - case QS(MP_QSTR_mac): { - uint8_t mac[6]; - 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)); - default: - goto unknown; - } - } - case QS(MP_QSTR_essid): - 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): - req_if = WIFI_IF_AP; - val = mp_obj_new_bool(cfg.ap.ssid_hidden); - break; - case QS(MP_QSTR_authmode): - req_if = WIFI_IF_AP; - val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode); - break; - case QS(MP_QSTR_channel): - req_if = WIFI_IF_AP; - val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); - break; - case QS(MP_QSTR_dhcp_hostname): { - const char *s; - ESP_EXCEPTIONS(tcpip_adapter_get_hostname(self->if_id, &s)); - val = mp_obj_new_str(s, strlen(s)); - break; - } - case QS(MP_QSTR_max_clients): { - val = MP_OBJ_NEW_SMALL_INT(cfg.ap.max_connection); - break; - } - case QS(MP_QSTR_reconnects): - req_if = WIFI_IF_STA; - int rec = conf_wifi_sta_reconnects - 1; - val = MP_OBJ_NEW_SMALL_INT(rec); - break; - default: - goto unknown; - } - -#undef QS - - // We post-check interface requirements to save on code size - if (req_if >= 0) { - require_if(args[0], req_if); - } - - return val; - -unknown: - mp_raise_ValueError(MP_ERROR_TEXT("unknown config param")); -} -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) }, - { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) }, - { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) }, - { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) }, - { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) }, - { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) }, - { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table); - -const mp_obj_type_t wlan_if_type = { - { &mp_type_type }, - .name = MP_QSTR_WLAN, - .locals_dict = (mp_obj_t)&wlan_if_locals_dict, -}; - STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode); +#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0) +#define TEST_WIFI_AUTH_MAX 9 +#else +#define TEST_WIFI_AUTH_MAX 8 +#endif +_Static_assert(WIFI_AUTH_MAX == TEST_WIFI_AUTH_MAX, "Synchronize WIFI_AUTH_XXX constants with the ESP-IDF. Look at esp-idf/components/esp_wifi/include/esp_wifi_types.h"); + 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) }, + + #if MICROPY_PY_NETWORK_WLAN { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) }, + #endif #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32) { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) }, @@ -786,6 +234,8 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) }, #if MODNETWORK_INCLUDE_CONSTANTS + + #if MICROPY_PY_NETWORK_WLAN { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(WIFI_IF_STA)}, { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(WIFI_IF_AP)}, @@ -799,11 +249,13 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) }, { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) }, { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_ENTERPRISE), MP_ROM_INT(WIFI_AUTH_WPA2_ENTERPRISE) }, - #if 0 // TODO: Remove this #if/#endif when lastest ISP IDF will be used { MP_ROM_QSTR(MP_QSTR_AUTH_WPA3_PSK), MP_ROM_INT(WIFI_AUTH_WPA3_PSK) }, { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_WPA3_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_WPA3_PSK) }, + #if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0) + { MP_ROM_QSTR(MP_QSTR_AUTH_WAPI_PSK), MP_ROM_INT(WIFI_AUTH_WAPI_PSK) }, #endif { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) }, + #endif #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32) { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) }, diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h index be6aa6706..7bcfa0e6f 100644 --- a/ports/esp32/modnetwork.h +++ b/ports/esp32/modnetwork.h @@ -26,14 +26,39 @@ #ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H #define MICROPY_INCLUDED_ESP32_MODNETWORK_H +#include "esp_event.h" + enum { PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041 }; enum { ETH_INITIALIZED, ETH_STARTED, ETH_STOPPED, ETH_CONNECTED, ETH_DISCONNECTED, ETH_GOT_IP }; +// Cases similar to ESP8266 user_interface.h +// Error cases are referenced from wifi_err_reason_t in ESP-IDF +enum { + STAT_IDLE = 1000, + STAT_CONNECTING = 1001, + STAT_GOT_IP = 1010, +}; + +typedef struct _wlan_if_obj_t { + mp_obj_base_t base; + int if_id; +} wlan_if_obj_t; + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj); 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); +NORETURN void esp_exceptions_helper(esp_err_t e); + +static inline void esp_exceptions(esp_err_t e) { + if (e != ESP_OK) { + esp_exceptions_helper(e); + } +} + void usocket_events_deinit(void); +void network_wlan_event_handler(system_event_t *event); #endif diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 75b00eadb..585e1f091 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -7,6 +7,8 @@ #include #include #include "esp_system.h" +#include "freertos/FreeRTOS.h" +#include "driver/i2s.h" // object representation and NLR handling #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) @@ -30,6 +32,8 @@ // optimisations #define MICROPY_OPT_COMPUTED_GOTO (1) +#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1) +#define MICROPY_OPT_MAP_LOOKUP_CACHE (1) #define MICROPY_OPT_MPZ_BITWISE (1) // Python internal features @@ -158,16 +162,26 @@ #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_BITSTREAM (1) #define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_PWM (1) +#define MICROPY_PY_MACHINE_PWM_INIT (1) +#define MICROPY_PY_MACHINE_PWM_DUTY (1) +#define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS (1) +#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/esp32/machine_pwm.c" #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SOFTI2C (1) #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (0) #define MICROPY_PY_MACHINE_SPI_LSB (1) +#define MICROPY_PY_MACHINE_SOFTSPI (1) #ifndef MICROPY_PY_MACHINE_DAC #define MICROPY_PY_MACHINE_DAC (1) #endif #ifndef MICROPY_PY_MACHINE_I2S #define MICROPY_PY_MACHINE_I2S (1) #endif +#ifndef MICROPY_PY_NETWORK_WLAN +#define MICROPY_PY_NETWORK_WLAN (1) +#endif #ifndef MICROPY_HW_ENABLE_SDCARD #define MICROPY_HW_ENABLE_SDCARD (1) #endif @@ -180,6 +194,8 @@ #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_BTREE (1) +#define MICROPY_PY_ONEWIRE (1) +#define MICROPY_PY_UPLATFORM (1) #define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) #define MICROPY_PY_BLUETOOTH_RANDOM_ADDR (1) #define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME ("ESP32") @@ -299,6 +315,7 @@ struct mp_bluetooth_nimble_root_pointers_t; const char *readline_hist[8]; \ mp_obj_t machine_pin_irq_handler[40]; \ struct _machine_timer_obj_t *machine_timer_obj_head; \ + struct _machine_i2s_obj_t *machine_i2s_obj[I2S_NUM_MAX]; \ MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE // type definitions for the specific machine @@ -341,6 +358,12 @@ void *esp_native_code_commit(void *, size_t, void *); #endif // Functions that should go in IRAM +#define MICROPY_WRAP_MP_BINARY_OP(f) IRAM_ATTR f +#define MICROPY_WRAP_MP_EXECUTE_BYTECODE(f) IRAM_ATTR f +#define MICROPY_WRAP_MP_LOAD_GLOBAL(f) IRAM_ATTR f +#define MICROPY_WRAP_MP_LOAD_NAME(f) IRAM_ATTR f +#define MICROPY_WRAP_MP_MAP_LOOKUP(f) IRAM_ATTR f +#define MICROPY_WRAP_MP_OBJ_GET_TYPE(f) IRAM_ATTR f #define MICROPY_WRAP_MP_SCHED_EXCEPTION(f) IRAM_ATTR f #define MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(f) IRAM_ATTR f @@ -356,6 +379,11 @@ typedef long mp_off_t; // board specifics #define MICROPY_PY_SYS_PLATFORM "esp32" +// ESP32-S3 extended IO for 47 & 48 +#ifndef MICROPY_HW_ESP32S3_EXTENDED_IO +#define MICROPY_HW_ESP32S3_EXTENDED_IO (1) +#endif + #ifndef MICROPY_HW_ENABLE_MDNS_QUERIES #define MICROPY_HW_ENABLE_MDNS_QUERIES (1) #endif @@ -363,3 +391,9 @@ typedef long mp_off_t; #ifndef MICROPY_HW_ENABLE_MDNS_RESPONDER #define MICROPY_HW_ENABLE_MDNS_RESPONDER (1) #endif + +#ifndef MICROPY_BOARD_STARTUP +#define MICROPY_BOARD_STARTUP boardctrl_startup +#endif + +void boardctrl_startup(void); diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h index 2dad8fa92..01c14ad70 100644 --- a/ports/esp32/mphalport.h +++ b/ports/esp32/mphalport.h @@ -35,6 +35,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#define MICROPY_PLATFORM_VERSION "IDF" IDF_VER + // The core that the MicroPython task(s) are pinned to. // Until we move to IDF 4.2+, we need NimBLE on core 0, and for synchronisation // with the ringbuffer and scheduler MP needs to be on the same core. diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c index f575d99e6..9d1c4a758 100644 --- a/ports/esp32/mpthreadport.c +++ b/ports/esp32/mpthreadport.c @@ -59,14 +59,19 @@ 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); // create the first entry in the linked list of all threads - thread = &thread_entry0; - thread->id = xTaskGetCurrentTaskHandle(); - thread->ready = 1; - thread->arg = NULL; - thread->stack = stack; - thread->stack_len = stack_len; - thread->next = NULL; + thread_entry0.id = xTaskGetCurrentTaskHandle(); + thread_entry0.ready = 1; + thread_entry0.arg = NULL; + thread_entry0.stack = stack; + thread_entry0.stack_len = stack_len; + thread_entry0.next = NULL; mp_thread_mutex_init(&thread_mutex); + + // memory barrier to ensure above data is committed + __sync_synchronize(); + + // vPortCleanUpTCB needs the thread ready after thread_mutex is ready + thread = &thread_entry0; } void mp_thread_gc_others(void) { diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c index 34e5cba25..f302d70fe 100644 --- a/ports/esp32/network_lan.c +++ b/ports/esp32/network_lan.c @@ -249,14 +249,13 @@ STATIC mp_obj_t lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed")); } lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); - #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) if (kwargs->used != 0) { for (size_t i = 0; i < kwargs->alloc; i++) { if (mp_map_slot_is_filled(kwargs, i)) { - switch ((uintptr_t)kwargs->table[i].key) { - case QS(MP_QSTR_mac): { + switch (mp_obj_str_get_qstr(kwargs->table[i].key)) { + case MP_QSTR_mac: { mp_buffer_info_t bufinfo; mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ); if (bufinfo.len != 6) { @@ -279,8 +278,8 @@ STATIC mp_obj_t lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs mp_obj_t val = mp_const_none; - switch ((uintptr_t)args[1]) { - case QS(MP_QSTR_mac): { + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_mac: { uint8_t mac[6]; esp_eth_ioctl(self->eth_handle, ETH_CMD_G_MAC_ADDR, mac); return mp_obj_new_bytes(mac, sizeof(mac)); diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c new file mode 100644 index 000000000..8702ca770 --- /dev/null +++ b/ports/esp32/network_wlan.c @@ -0,0 +1,574 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * and Mnemote Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016, 2017 Nick Moore @mnemote + * Copyright (c) 2017 "Eric Poulsen" + * + * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky + * And the ESP IDF example code which is Public Domain / CC0 + * + * 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/objlist.h" +#include "py/runtime.h" +#include "modnetwork.h" + +#include "esp_wifi.h" +#include "esp_log.h" +#include "mdns.h" + +#if MICROPY_PY_NETWORK_WLAN + +#if (WIFI_MODE_STA & WIFI_MODE_AP != WIFI_MODE_NULL || WIFI_MODE_STA | WIFI_MODE_AP != WIFI_MODE_APSTA) +#error WIFI_MODE_STA and WIFI_MODE_AP are supposed to be bitfields! +#endif + +STATIC const mp_obj_type_t wlan_if_type; +STATIC const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA}; +STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP}; + +// Set to "true" if esp_wifi_start() was called +static bool wifi_started = false; + +// Set to "true" if the STA interface is requested to be connected by the +// user, used for automatic reassociation. +static bool wifi_sta_connect_requested = false; + +// Set to "true" if the STA interface is connected to wifi and has IP address. +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 + +static uint8_t conf_wifi_sta_reconnects = 0; +static uint8_t wifi_sta_reconnects; + +// 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. +void network_wlan_event_handler(system_event_t *event) { + switch (event->event_id) { + case SYSTEM_EVENT_STA_START: + ESP_LOGI("wifi", "STA_START"); + wifi_sta_reconnects = 0; + break; + case SYSTEM_EVENT_STA_CONNECTED: + ESP_LOGI("network", "CONNECTED"); + break; + case SYSTEM_EVENT_STA_GOT_IP: + ESP_LOGI("network", "GOT_IP"); + wifi_sta_connected = true; + 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 + // auto-reassociate. + system_event_sta_disconnected_t *disconn = &event->event_info.disconnected; + char *message = ""; + wifi_sta_disconn_reason = disconn->reason; + switch (disconn->reason) { + case WIFI_REASON_BEACON_TIMEOUT: + // AP has dropped out; try to reconnect. + message = "\nbeacon timeout"; + break; + case WIFI_REASON_NO_AP_FOUND: + // AP may not exist, or it may have momentarily dropped out; try to reconnect. + 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"; + break; + default: + // Let other errors through and try to reconnect. + break; + } + ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message); + + wifi_sta_connected = false; + if (wifi_sta_connect_requested) { + wifi_mode_t mode; + if (esp_wifi_get_mode(&mode) != ESP_OK) { + break; + } + if (!(mode & WIFI_MODE_STA)) { + break; + } + if (conf_wifi_sta_reconnects) { + ESP_LOGI("wifi", "reconnect counter=%d, max=%d", + wifi_sta_reconnects, conf_wifi_sta_reconnects); + if (++wifi_sta_reconnects >= conf_wifi_sta_reconnects) { + break; + } + } + esp_err_t e = esp_wifi_connect(); + if (e != ESP_OK) { + ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e); + } + } + break; + } + default: + break; + } +} + +STATIC void require_if(mp_obj_t wlan_if, int if_no) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if); + if (self->if_id != if_no) { + mp_raise_msg(&mp_type_OSError, if_no == WIFI_IF_STA ? MP_ERROR_TEXT("STA required") : MP_ERROR_TEXT("AP required")); + } +} + +STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { + static int initialized = 0; + if (!initialized) { + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_LOGD("modnetwork", "Initializing WiFi"); + esp_exceptions(esp_wifi_init(&cfg)); + esp_exceptions(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_LOGD("modnetwork", "Initialized"); + initialized = 1; + } + + int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA; + if (idx == WIFI_IF_STA) { + return MP_OBJ_FROM_PTR(&wlan_sta_obj); + } else if (idx == WIFI_IF_AP) { + return MP_OBJ_FROM_PTR(&wlan_ap_obj); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("invalid WLAN interface identifier")); + } +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan); + +STATIC mp_obj_t network_wlan_active(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + wifi_mode_t mode; + if (!wifi_started) { + mode = WIFI_MODE_NULL; + } else { + esp_exceptions(esp_wifi_get_mode(&mode)); + } + + int bit = (self->if_id == WIFI_IF_STA) ? WIFI_MODE_STA : WIFI_MODE_AP; + + if (n_args > 1) { + bool active = mp_obj_is_true(args[1]); + mode = active ? (mode | bit) : (mode & ~bit); + if (mode == WIFI_MODE_NULL) { + if (wifi_started) { + esp_exceptions(esp_wifi_stop()); + wifi_started = false; + } + } else { + esp_exceptions(esp_wifi_set_mode(mode)); + if (!wifi_started) { + esp_exceptions(esp_wifi_start()); + wifi_started = true; + } + } + } + + return (mode & bit) ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_wlan_active_obj, 1, 2, network_wlan_active); + +STATIC mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_ssid, ARG_password, ARG_bssid }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_bssid, 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 - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + wifi_config_t wifi_sta_config = {0}; + + // configure any parameters that are given + if (n_args > 1) { + 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); + memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); + } + if (args[ARG_password].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_password].u_obj, &len); + memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password))); + } + if (args[ARG_bssid].u_obj != mp_const_none) { + p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len); + if (len != sizeof(wifi_sta_config.sta.bssid)) { + mp_raise_ValueError(NULL); + } + wifi_sta_config.sta.bssid_set = 1; + memcpy(wifi_sta_config.sta.bssid, p, sizeof(wifi_sta_config.sta.bssid)); + } + esp_exceptions(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config)); + } + + wifi_sta_reconnects = 0; + // connect to the WiFi AP + MP_THREAD_GIL_EXIT(); + esp_exceptions(esp_wifi_connect()); + MP_THREAD_GIL_ENTER(); + wifi_sta_connect_requested = true; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_connect_obj, 1, network_wlan_connect); + +STATIC mp_obj_t network_wlan_disconnect(mp_obj_t self_in) { + wifi_sta_connect_requested = false; + esp_exceptions(esp_wifi_disconnect()); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_disconnect_obj, network_wlan_disconnect); + +STATIC mp_obj_t network_wlan_status(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + if (self->if_id == WIFI_IF_STA) { + // Case of no arg is only for the STA interface + if (wifi_sta_connected) { + // Happy path, connected with IP + return MP_OBJ_NEW_SMALL_INT(STAT_GOT_IP); + } else if (wifi_sta_connect_requested + && (conf_wifi_sta_reconnects == 0 + || wifi_sta_reconnects < conf_wifi_sta_reconnects)) { + // No connection or error, but is requested = Still connecting + return MP_OBJ_NEW_SMALL_INT(STAT_CONNECTING); + } else if (wifi_sta_disconn_reason == 0) { + // No activity, No error = Idle + return MP_OBJ_NEW_SMALL_INT(STAT_IDLE); + } else { + // Simply pass the error through from ESP-identifier + return MP_OBJ_NEW_SMALL_INT(wifi_sta_disconn_reason); + } + } + return mp_const_none; + } + + // one argument: return status based on query parameter + switch ((uintptr_t)args[1]) { + case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): { + // return list of connected stations, only if in soft-AP mode + require_if(args[0], WIFI_IF_AP); + wifi_sta_list_t station_list; + esp_exceptions(esp_wifi_ap_get_sta_list(&station_list)); + wifi_sta_info_t *stations = (wifi_sta_info_t *)station_list.sta; + mp_obj_t list = mp_obj_new_list(0, NULL); + for (int i = 0; i < station_list.num; ++i) { + mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL); + t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac)); + mp_obj_list_append(list, t); + } + return list; + } + 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(MP_ERROR_TEXT("unknown status param")); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_wlan_status_obj, 1, 2, network_wlan_status); + +STATIC mp_obj_t network_wlan_scan(mp_obj_t self_in) { + // check that STA mode is active + wifi_mode_t mode; + esp_exceptions(esp_wifi_get_mode(&mode)); + if ((mode & WIFI_MODE_STA) == 0) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("STA must be active")); + } + + mp_obj_t list = mp_obj_new_list(0, NULL); + wifi_scan_config_t config = { 0 }; + config.show_hidden = true; + MP_THREAD_GIL_EXIT(); + esp_err_t status = esp_wifi_scan_start(&config, 1); + MP_THREAD_GIL_ENTER(); + if (status == 0) { + uint16_t count = 0; + esp_exceptions(esp_wifi_scan_get_ap_num(&count)); + wifi_ap_record_t *wifi_ap_records = calloc(count, sizeof(wifi_ap_record_t)); + esp_exceptions(esp_wifi_scan_get_ap_records(&count, wifi_ap_records)); + for (uint16_t i = 0; i < count; i++) { + mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); + uint8_t *x = memchr(wifi_ap_records[i].ssid, 0, sizeof(wifi_ap_records[i].ssid)); + int ssid_len = x ? x - wifi_ap_records[i].ssid : sizeof(wifi_ap_records[i].ssid); + t->items[0] = mp_obj_new_bytes(wifi_ap_records[i].ssid, ssid_len); + t->items[1] = mp_obj_new_bytes(wifi_ap_records[i].bssid, sizeof(wifi_ap_records[i].bssid)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].primary); + t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].rssi); + t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].authmode); + t->items[5] = mp_const_false; // XXX hidden? + mp_obj_list_append(list, MP_OBJ_FROM_PTR(t)); + } + free(wifi_ap_records); + } + return list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_scan_obj, network_wlan_scan); + +STATIC mp_obj_t network_wlan_isconnected(mp_obj_t self_in) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->if_id == WIFI_IF_STA) { + return mp_obj_new_bool(wifi_sta_connected); + } else { + wifi_sta_list_t sta; + esp_wifi_ap_get_sta_list(&sta); + return mp_obj_new_bool(sta.num != 0); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_isconnected_obj, network_wlan_isconnected); + +STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + if (n_args != 1 && kwargs->used != 0) { + mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed")); + } + + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + bool is_wifi = self->if_id == WIFI_IF_AP || self->if_id == WIFI_IF_STA; + + wifi_config_t cfg; + if (is_wifi) { + esp_exceptions(esp_wifi_get_config(self->if_id, &cfg)); + } + + 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; + + switch (mp_obj_str_get_qstr(kwargs->table[i].key)) { + case MP_QSTR_mac: { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != 6) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length")); + } + esp_exceptions(esp_wifi_set_mac(self->if_id, bufinfo.buf)); + break; + } + case MP_QSTR_essid: { + req_if = WIFI_IF_AP; + 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); + cfg.ap.ssid_len = len; + break; + } + case MP_QSTR_hidden: { + req_if = WIFI_IF_AP; + cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value); + break; + } + case MP_QSTR_authmode: { + req_if = WIFI_IF_AP; + cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value); + break; + } + case MP_QSTR_password: { + req_if = WIFI_IF_AP; + 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); + cfg.ap.password[len] = 0; + break; + } + case MP_QSTR_channel: { + req_if = WIFI_IF_AP; + cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); + break; + } + case MP_QSTR_dhcp_hostname: { + const char *s = mp_obj_str_get_str(kwargs->table[i].value); + esp_exceptions(tcpip_adapter_set_hostname(self->if_id, s)); + break; + } + case MP_QSTR_max_clients: { + req_if = WIFI_IF_AP; + cfg.ap.max_connection = mp_obj_get_int(kwargs->table[i].value); + break; + } + case MP_QSTR_reconnects: { + int reconnects = mp_obj_get_int(kwargs->table[i].value); + req_if = WIFI_IF_STA; + // parameter reconnects == -1 means to retry forever. + // here means conf_wifi_sta_reconnects == 0 to retry forever. + conf_wifi_sta_reconnects = (reconnects == -1) ? 0 : reconnects + 1; + break; + } + default: + goto unknown; + } + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + } + } + + esp_exceptions(esp_wifi_set_config(self->if_id, &cfg)); + + return mp_const_none; + } + + // Get config + + if (n_args != 2) { + mp_raise_TypeError(MP_ERROR_TEXT("can query only one param")); + } + + int req_if = -1; + mp_obj_t val = mp_const_none; + + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_mac: { + uint8_t mac[6]; + 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)); + default: + goto unknown; + } + } + case MP_QSTR_essid: + 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 MP_QSTR_hidden: + req_if = WIFI_IF_AP; + val = mp_obj_new_bool(cfg.ap.ssid_hidden); + break; + case MP_QSTR_authmode: + req_if = WIFI_IF_AP; + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode); + break; + case MP_QSTR_channel: + req_if = WIFI_IF_AP; + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); + break; + case MP_QSTR_dhcp_hostname: { + const char *s; + esp_exceptions(tcpip_adapter_get_hostname(self->if_id, &s)); + val = mp_obj_new_str(s, strlen(s)); + break; + } + case MP_QSTR_max_clients: { + val = MP_OBJ_NEW_SMALL_INT(cfg.ap.max_connection); + break; + } + case MP_QSTR_reconnects: + req_if = WIFI_IF_STA; + int rec = conf_wifi_sta_reconnects - 1; + val = MP_OBJ_NEW_SMALL_INT(rec); + break; + default: + goto unknown; + } + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + + return val; + +unknown: + mp_raise_ValueError(MP_ERROR_TEXT("unknown config param")); +} +MP_DEFINE_CONST_FUN_OBJ_KW(network_wlan_config_obj, 1, network_wlan_config); + +STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_wlan_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_wlan_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&network_wlan_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_wlan_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_wlan_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_wlan_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_wlan_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table); + +STATIC const mp_obj_type_t wlan_if_type = { + { &mp_type_type }, + .name = MP_QSTR_WLAN, + .locals_dict = (mp_obj_t)&wlan_if_locals_dict, +}; + +#endif // MICROPY_PY_NETWORK_WLAN diff --git a/ports/esp32/partitions-8MiB.csv b/ports/esp32/partitions-8MiB.csv new file mode 100644 index 000000000..582d3b50e --- /dev/null +++ b/ports/esp32/partitions-8MiB.csv @@ -0,0 +1,7 @@ +# Notes: the offset of the partition table itself is set in +# $IDF_PATH/components/partition_table/Kconfig.projbuild. +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 0x1F0000, +vfs, data, fat, 0x200000, 0x600000, diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c index 480b364a5..58fc0c6c6 100644 --- a/ports/esp32/uart.c +++ b/ports/esp32/uart.c @@ -45,13 +45,18 @@ void uart_init(void) { // all code executed in ISR must be in IRAM, and any const data must be in DRAM STATIC void IRAM_ATTR uart_irq_handler(void *arg) { volatile uart_dev_t *uart = &UART0; + #if CONFIG_IDF_TARGET_ESP32S3 + uart->int_clr.rxfifo_full_int_clr = 1; + uart->int_clr.rxfifo_tout_int_clr = 1; + #else uart->int_clr.rxfifo_full = 1; - uart->int_clr.frm_err = 1; uart->int_clr.rxfifo_tout = 1; + uart->int_clr.frm_err = 1; + #endif while (uart->status.rxfifo_cnt) { #if CONFIG_IDF_TARGET_ESP32 uint8_t c = uart->fifo.rw_byte; - #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 + #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 uint8_t c = READ_PERI_REG(UART_FIFO_AHB_REG(0)); // UART0 #endif if (c == mp_interrupt_char) { diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c index 85a7a11c9..5a613d244 100644 --- a/ports/esp32/usb.c +++ b/ports/esp32/usb.c @@ -36,6 +36,7 @@ #define CDC_ITF TINYUSB_CDC_ACM_0 static uint8_t usb_rx_buf[CONFIG_USB_CDC_RX_BUFSIZE]; +static uint8_t usb_cdc_connected; static void usb_callback_rx(int itf, cdcacm_event_t *event) { // TODO: what happens if more chars come in during this function, are they lost? @@ -58,6 +59,13 @@ static void usb_callback_rx(int itf, cdcacm_event_t *event) { } } +void usb_callback_line_state_changed(int itf, cdcacm_event_t *event) { + int dtr = event->line_state_changed_data.dtr; + int rts = event->line_state_changed_data.rts; + // If dtr && rts are both true, the CDC is connected to a HOST. + usb_cdc_connected = dtr && rts; +} + void usb_init(void) { // Initialise the USB with defaults. tinyusb_config_t tusb_cfg = {0}; @@ -70,22 +78,21 @@ void usb_init(void) { .rx_unread_buf_sz = 256, .callback_rx = &usb_callback_rx, .callback_rx_wanted_char = NULL, - .callback_line_state_changed = NULL, + .callback_line_state_changed = &usb_callback_line_state_changed, .callback_line_coding_changed = NULL }; + usb_cdc_connected = 0; ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg)); + } void usb_tx_strn(const char *str, size_t len) { - while (len) { - size_t l = len; - if (l > CONFIG_USB_CDC_TX_BUFSIZE) { - l = CONFIG_USB_CDC_TX_BUFSIZE; - } - tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, l); - tinyusb_cdcacm_write_flush(CDC_ITF, pdMS_TO_TICKS(1000)); + // Write out the data to the CDC interface, but only while the USB host is connected. + while (usb_cdc_connected && len) { + size_t l = tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, len); str += l; len -= l; + tud_cdc_n_write_flush(CDC_ITF); } } diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 9ea4498f4..d0afe73ea 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -27,8 +27,6 @@ AXTLS_DEFS_EXTRA = -Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=4096 BTREE_DEFS_EXTRA = -DDEFPSIZE=1024 -DMINCACHE=3 FROZEN_MANIFEST ?= boards/manifest.py -FROZEN_DIR ?= -FROZEN_MPY_DIR ?= # include py core make definitions include $(TOP)/py/py.mk @@ -96,7 +94,6 @@ SRC_C = \ modmachine.c \ machine_bitstream.c \ machine_pin.c \ - machine_pwm.c \ machine_rtc.c \ machine_adc.c \ machine_uart.c \ @@ -197,12 +194,9 @@ $(BUILD)/uart.o: $(CONFVARS_FILE) FROZEN_EXTRA_DEPS = $(CONFVARS_FILE) -ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),) +ifneq ($(FROZEN_MANIFEST),) 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 diff --git a/ports/esp8266/boards/GENERIC/board.json b/ports/esp8266/boards/GENERIC/board.json new file mode 100644 index 000000000..46c2659d8 --- /dev/null +++ b/ports/esp8266/boards/GENERIC/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "WiFi" + ], + "id": "esp8266", + "images": [], + "mcu": "esp8266", + "product": "ESP8266 with 2MiB+ flash", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "variants": { + "ota": "OTA compatible" + }, + "vendor": "Espressif" +} diff --git a/ports/esp8266/boards/GENERIC/board.md b/ports/esp8266/boards/GENERIC/board.md new file mode 100644 index 000000000..b93ca509f --- /dev/null +++ b/ports/esp8266/boards/GENERIC/board.md @@ -0,0 +1,19 @@ +The following are daily builds of the ESP8266 firmware for boards with at +least 2MiB of flash. They have the latest features and bug fixes, WebREPL is +not automatically started, and debugging is enabled by default. + +Note: v1.12-334 and newer (including v1.13) require an ESP8266 module with +2MiB of flash or more, and use littlefs as the filesystem by default. When +upgrading from older firmware please backup your files first, and either +erase all flash before upgrading, or after upgrading execute +`uos.VfsLfs2.mkfs(bdev)`. + +### OTA builds +Over-The-Air (OTA) builds of the ESP8266 firmware are also provided. + +The first time you use this build you need to flash one of the "initial image" +images using esptool.py as described above. After that, you can update the +firmware over the air using the "OTA update" file in conjunction with the +ota-client script from yaota8266. The "OTA update" files are digitally signed +and will only work with the provided "initial image" files, and vice versa. +(Note: this feature is work-in-progress.) diff --git a/ports/esp8266/boards/GENERIC/mpconfigboard.h b/ports/esp8266/boards/GENERIC/mpconfigboard.h index d33943df8..e4991ba97 100644 --- a/ports/esp8266/boards/GENERIC/mpconfigboard.h +++ b/ports/esp8266/boards/GENERIC/mpconfigboard.h @@ -11,6 +11,7 @@ #define MICROPY_READER_VFS (MICROPY_VFS) #define MICROPY_VFS (1) +#define MICROPY_PY_FSTRINGS (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_IO_FILEIO (1) diff --git a/ports/esp8266/boards/GENERIC_1M/board.json b/ports/esp8266/boards/GENERIC_1M/board.json new file mode 100644 index 000000000..2ef4bd99f --- /dev/null +++ b/ports/esp8266/boards/GENERIC_1M/board.json @@ -0,0 +1,16 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "WiFi" + ], + "id": "esp8266-1m", + "images": [], + "mcu": "esp8266", + "product": "ESP8266 with 1MiB flash", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp8266/boards/GENERIC_1M/board.md b/ports/esp8266/boards/GENERIC_1M/board.md new file mode 100644 index 000000000..4a0e67707 --- /dev/null +++ b/ports/esp8266/boards/GENERIC_1M/board.md @@ -0,0 +1,5 @@ +The following are daily builds of the ESP8266 firmware tailored for modules with +only 1MiB of flash. This firmware uses littlefs as the filesystem. +When upgrading from older firmware that uses a FAT filesystem please backup your files +first, and either erase all flash before upgrading, or after upgrading execute +`uos.VfsLfs2.mkfs(bdev)`. diff --git a/ports/esp8266/boards/GENERIC_512K/board.json b/ports/esp8266/boards/GENERIC_512K/board.json new file mode 100644 index 000000000..10050592c --- /dev/null +++ b/ports/esp8266/boards/GENERIC_512K/board.json @@ -0,0 +1,16 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "WiFi" + ], + "id": "esp8266-512k", + "images": [], + "mcu": "esp8266", + "product": "ESP8266 with 512kiB flash", + "thumbnail": "", + "url": "https://www.espressif.com/en/products/modules", + "vendor": "Espressif" +} diff --git a/ports/esp8266/boards/GENERIC_512K/board.md b/ports/esp8266/boards/GENERIC_512K/board.md new file mode 100644 index 000000000..1f6e2c790 --- /dev/null +++ b/ports/esp8266/boards/GENERIC_512K/board.md @@ -0,0 +1,3 @@ +The following are daily builds of the ESP8266 firmware tailored for modules with +only 512kiB of flash. Certain features are disabled to get the firmware down +to this size. diff --git a/ports/esp8266/boards/deploy.md b/ports/esp8266/boards/deploy.md new file mode 100644 index 000000000..520316367 --- /dev/null +++ b/ports/esp8266/boards/deploy.md @@ -0,0 +1 @@ +Program your board using the esptool.py program as described [the tutorial](http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html#deploying-the-firmware). diff --git a/ports/esp8266/boards/esp8266_common.ld b/ports/esp8266/boards/esp8266_common.ld index f40ff1e5f..ae1509fae 100644 --- a/ports/esp8266/boards/esp8266_common.ld +++ b/ports/esp8266/boards/esp8266_common.ld @@ -144,7 +144,7 @@ SECTIONS *shared/timeutils/*.o*(.literal*, .text*) *drivers/bus/*.o(.literal* .text*) - build-*/main.o(.literal* .text*) + */main.o(.literal* .text*) *fatfs_port.o(.literal* .text*) *gccollect.o(.literal* .text*) *gchelper.o(.literal* .text*) @@ -182,7 +182,7 @@ SECTIONS */frozen.o(.rodata.mp_frozen_content) /* frozen modules */ /* for -mforce-l32 */ - build-*/*.o(.rodata*) + */*.o(.rodata*) _irom0_text_end = ABSOLUTE(.); } >irom0_0_seg :irom0_0_phdr diff --git a/ports/esp8266/etshal.h b/ports/esp8266/etshal.h index f7b34b835..7d0855a2a 100644 --- a/ports/esp8266/etshal.h +++ b/ports/esp8266/etshal.h @@ -6,22 +6,10 @@ // see http://esp8266-re.foogod.com/wiki/Random_Number_Generator #define WDEV_HWRNG ((volatile uint32_t *)0x3ff20e44) -void ets_delay_us(uint16_t us); -void ets_intr_lock(void); -void ets_intr_unlock(void); void ets_isr_mask(uint32_t mask); void ets_isr_unmask(uint32_t mask); -void ets_isr_attach(int irq_no, void (*handler)(void *), void *arg); -void ets_install_putc1(); -void uart_div_modify(uint8_t uart, uint32_t divisor); -void ets_set_idle_cb(void (*handler)(void *), void *arg); -void ets_timer_arm_new(os_timer_t *tim, uint32_t millis, bool repeat, bool is_milli_timer); -void ets_timer_setfn(os_timer_t *tim, ETSTimerFunc callback, void *cb_data); -void ets_timer_disarm(os_timer_t *tim); - -extern void ets_wdt_disable(void); -extern void wdt_feed(void); +void ets_wdt_disable(void); // Opaque structure #ifndef MD5_CTX @@ -32,12 +20,6 @@ void MD5Init(MD5_CTX *context); void MD5Update(MD5_CTX *context, const void *data, unsigned int len); void MD5Final(unsigned char digest[16], MD5_CTX *context); -// These prototypes are for recent SDKs with "malloc tracking" -void *pvPortMalloc(size_t sz, const char *fname, unsigned line); -void *pvPortZalloc(size_t sz, const char *fname, unsigned line); -void *pvPortRealloc(void *p, unsigned sz, const char *fname, unsigned line); -void vPortFree(void *p, const char *fname, unsigned line); - uint32_t SPIRead(uint32_t offset, void *buf, uint32_t len); uint32_t SPIWrite(uint32_t offset, const void *buf, uint32_t len); uint32_t SPIEraseSector(int sector); diff --git a/ports/esp8266/machine_pwm.c b/ports/esp8266/machine_pwm.c index 1d6a6cfe5..f8cd937b8 100644 --- a/ports/esp8266/machine_pwm.c +++ b/ports/esp8266/machine_pwm.c @@ -24,28 +24,25 @@ * THE SOFTWARE. */ -#include -#include - -#include "esppwm.h" - #include "py/runtime.h" #include "modmachine.h" -typedef struct _pyb_pwm_obj_t { +#include "esppwm.h" + +typedef struct _machine_pwm_obj_t { mp_obj_base_t base; pyb_pin_obj_t *pin; uint8_t active; uint8_t channel; -} pyb_pwm_obj_t; +} machine_pwm_obj_t; STATIC bool pwm_inited = false; /******************************************************************************/ // MicroPython bindings for PWM -STATIC void pyb_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); +STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "PWM(%u", self->pin->phys_port); if (self->active) { mp_printf(print, ", freq=%u, duty=%u", @@ -54,7 +51,7 @@ STATIC void pyb_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki mp_printf(print, ")"); } -STATIC void pyb_pwm_init_helper(pyb_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_freq, ARG_duty }; static const mp_arg_t allowed_args[] = { { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, @@ -80,13 +77,13 @@ STATIC void pyb_pwm_init_helper(pyb_pwm_obj_t *self, size_t n_args, const mp_obj pwm_start(); } -STATIC mp_obj_t pyb_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); pyb_pin_obj_t *pin = mp_obj_get_pin_obj(args[0]); // create PWM object from the given pin - pyb_pwm_obj_t *self = m_new_obj(pyb_pwm_obj_t); - self->base.type = &pyb_pwm_type; + machine_pwm_obj_t *self = m_new_obj(machine_pwm_obj_t); + self->base.type = &machine_pwm_type; self->pin = pin; self->active = 0; self->channel = -1; @@ -100,71 +97,39 @@ STATIC mp_obj_t pyb_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_ // start the PWM running for this channel mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - pyb_pwm_init_helper(self, n_args - 1, args + 1, &kw_args); + mp_machine_pwm_init_helper(self, n_args - 1, args + 1, &kw_args); return MP_OBJ_FROM_PTR(self); } -STATIC mp_obj_t pyb_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - pyb_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pwm_init_obj, 1, pyb_pwm_init); - -STATIC mp_obj_t pyb_pwm_deinit(mp_obj_t self_in) { - pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); +STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) { pwm_delete(self->channel); self->active = 0; pwm_start(); - return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pwm_deinit_obj, pyb_pwm_deinit); -STATIC mp_obj_t pyb_pwm_freq(size_t n_args, const mp_obj_t *args) { - // pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); - if (n_args == 1) { - // get - return MP_OBJ_NEW_SMALL_INT(pwm_get_freq(0)); - } else { - // set - pwm_set_freq(mp_obj_get_int(args[1]), 0); - pwm_start(); - return mp_const_none; - } +STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(pwm_get_freq(0)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_freq_obj, 1, 2, pyb_pwm_freq); -STATIC mp_obj_t pyb_pwm_duty(size_t n_args, const mp_obj_t *args) { - pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); +STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) { + pwm_set_freq(freq, 0); + pwm_start(); +} + +STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self) { if (!self->active) { pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func); self->active = 1; } - if (n_args == 1) { - // get - return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel)); - } else { - // set - pwm_set_duty(mp_obj_get_int(args[1]), self->channel); - pwm_start(); - return mp_const_none; - } + return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_duty_obj, 1, 2, pyb_pwm_duty); -STATIC const mp_rom_map_elem_t pyb_pwm_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_pwm_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_pwm_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_pwm_freq_obj) }, - { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&pyb_pwm_duty_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(pyb_pwm_locals_dict, pyb_pwm_locals_dict_table); - -const mp_obj_type_t pyb_pwm_type = { - { &mp_type_type }, - .name = MP_QSTR_PWM, - .print = pyb_pwm_print, - .make_new = pyb_pwm_make_new, - .locals_dict = (mp_obj_dict_t *)&pyb_pwm_locals_dict, -}; +STATIC void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty) { + if (!self->active) { + pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func); + self->active = 1; + } + pwm_set_duty(duty, self->channel); + pwm_start(); +} diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index 404188346..5d7debced 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -52,11 +52,8 @@ STATIC void mp_reset(void) { mp_hal_init(); gc_init(heap, heap + sizeof(heap)); mp_init(); - mp_obj_list_init(mp_sys_path, 0); - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_)); - mp_obj_list_init(mp_sys_argv, 0); #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA extern void esp_native_code_init(void); esp_native_code_init(); diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index 6cd458343..39a890f56 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -39,6 +39,7 @@ #include "extmod/machine_mem.h" #include "extmod/machine_signal.h" #include "extmod/machine_pulse.h" +#include "extmod/machine_pwm.h" #include "extmod/machine_i2c.h" #include "extmod/machine_spi.h" #include "modmachine.h" @@ -423,7 +424,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&esp_wdt_type) }, { 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_PWM), MP_ROM_PTR(&machine_pwm_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 diff --git a/ports/esp8266/modmachine.h b/ports/esp8266/modmachine.h index be4debd33..4a73d3b8e 100644 --- a/ports/esp8266/modmachine.h +++ b/ports/esp8266/modmachine.h @@ -4,7 +4,6 @@ #include "py/obj.h" extern const mp_obj_type_t pyb_pin_type; -extern const mp_obj_type_t pyb_pwm_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; diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index f0cd83aee..6988e09bd 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -351,9 +351,8 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs for (mp_uint_t i = 0; i < kwargs->alloc; 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): { + switch (mp_obj_str_get_qstr(kwargs->table[i].key)) { + case MP_QSTR_mac: { mp_buffer_info_t bufinfo; mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ); if (bufinfo.len != 6) { @@ -362,7 +361,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs wifi_set_macaddr(self->if_id, bufinfo.buf); break; } - case QS(MP_QSTR_essid): { + case MP_QSTR_essid: { req_if = SOFTAP_IF; size_t len; const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); @@ -371,17 +370,17 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs cfg.ap.ssid_len = len; break; } - case QS(MP_QSTR_hidden): { + case MP_QSTR_hidden: { req_if = SOFTAP_IF; cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value); break; } - case QS(MP_QSTR_authmode): { + case MP_QSTR_authmode: { req_if = SOFTAP_IF; cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value); break; } - case QS(MP_QSTR_password): { + case MP_QSTR_password: { req_if = SOFTAP_IF; size_t len; const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); @@ -390,12 +389,12 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs cfg.ap.password[len] = 0; break; } - case QS(MP_QSTR_channel): { + case MP_QSTR_channel: { req_if = SOFTAP_IF; cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); break; } - case QS(MP_QSTR_dhcp_hostname): { + case MP_QSTR_dhcp_hostname: { req_if = STATION_IF; if (self->if_id == STATION_IF) { const char *s = mp_obj_str_get_str(kwargs->table[i].value); @@ -406,7 +405,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 } } diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index c7e2f4a44..7d6d0a34c 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -81,9 +81,16 @@ #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_BITSTREAM (1) #define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_PWM (1) +#define MICROPY_PY_MACHINE_PWM_INIT (1) +#define MICROPY_PY_MACHINE_PWM_DUTY (1) +#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/esp8266/machine_pwm.c" #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SOFTI2C (1) #define MICROPY_PY_MACHINE_SPI (1) +#define MICROPY_PY_MACHINE_SOFTSPI (1) #define MICROPY_PY_UWEBSOCKET (1) +#define MICROPY_PY_ONEWIRE (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_WEBREPL_DELAY (20) #define MICROPY_PY_WEBREPL_STATIC_FILEBUF (1) diff --git a/ports/javascript/Makefile b/ports/javascript/Makefile index 3fac114f5..ba2680b2a 100644 --- a/ports/javascript/Makefile +++ b/ports/javascript/Makefile @@ -17,13 +17,6 @@ CFLAGS += -std=c99 -Wall -Werror -Wdouble-promotion -Wfloat-conversion CFLAGS += -O3 -DNDEBUG CFLAGS += $(INC) -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_SHARED = $(addprefix shared/,\ runtime/interrupt_char.c \ runtime/stdout_helpers.c \ diff --git a/ports/javascript/main.c b/ports/javascript/main.c index 7a04b8eea..04a853f66 100644 --- a/ports/javascript/main.c +++ b/ports/javascript/main.c @@ -91,10 +91,6 @@ void mp_js_init(int heap_size) { #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() { diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 818a2a3c8..32b114523 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -13,6 +13,24 @@ endif include ../../py/mkenv.mk include $(BOARD_DIR)/mpconfigboard.mk +LD_MEMORY_CONFIG_DEFINES += \ + MICROPY_HW_FLASH_TYPE=$(MICROPY_HW_FLASH_TYPE) \ + MICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) + +ifdef MICROPY_HW_FLASH_RESERVED +LD_MEMORY_CONFIG_DEFINES += MICROPY_HW_FLASH_RESERVED=$(MICROPY_HW_FLASH_RESERVED) +endif + +ifdef MICROPY_HW_SDRAM_AVAIL +CFLAGS += \ + -DMICROPY_HW_SDRAM_AVAIL=$(MICROPY_HW_SDRAM_AVAIL) \ + -DMICROPY_HW_SDRAM_SIZE=$(MICROPY_HW_SDRAM_SIZE) + +LD_MEMORY_CONFIG_DEFINES += \ + MICROPY_HW_SDRAM_AVAIL=$(MICROPY_HW_SDRAM_AVAIL) \ + MICROPY_HW_SDRAM_SIZE=$(MICROPY_HW_SDRAM_SIZE) +endif + # Qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h @@ -20,16 +38,18 @@ QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h # MicroPython feature configurations FROZEN_MANIFEST ?= boards/manifest.py MICROPY_VFS_LFS2 ?= 1 +MICROPY_VFS_FAT ?= 1 # Include py core make definitions include $(TOP)/py/py.mk -GIT_SUBMODULES = lib/tinyusb lib/nxp_driver +GIT_SUBMODULES = lib/tinyusb lib/nxp_driver lib/lwip lib/mbedtls MCU_DIR = lib/nxp_driver/sdk/devices/$(MCU_SERIES) -LD_FILES = boards/$(BOARD)/$(BOARD).ld boards/$(MCU_SERIES).ld boards/common.ld +LD_FILES = boards/$(MCU_SERIES).ld boards/common.ld MAKE_PINS = boards/make-pins.py +MAKE_FLEXRAM_LD = boards/make-flexram-config.py BOARD_PINS = $(BOARD_DIR)/pins.csv AF_FILE = boards/$(MCU_SERIES)_af.csv PREFIX_FILE = boards/mimxrt_prefix.c @@ -38,33 +58,49 @@ GEN_PINS_HDR = $(HEADER_BUILD)/pins.h GEN_PINS_QSTR = $(BUILD)/pins_qstr.h GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h GEN_PINS_AF_PY = $(BUILD)/pins_af.py +GEN_FLEXRAM_CONFIG_SRC = $(BUILD)/flexram_config.s # mcu driver cause following warnings #CFLAGS += -Wno-error=float-equal -Wno-error=nested-externs CFLAGS += -Wno-error=unused-parameter INC += -I. -INC += -I$(TOP) -INC += -I$(BUILD) +INC += -Ihal INC += -I$(BOARD_DIR) -INC += -I$(TOP)/lib/cmsis/inc +INC += -I$(BUILD) +INC += -I$(TOP) INC += -I$(TOP)/$(MCU_DIR) INC += -I$(TOP)/$(MCU_DIR)/drivers -INC += -I$(TOP)/$(MCU_DIR)/project_template -INC += -I$(TOP)/lib/tinyusb/src +INC += -I$(TOP)/lib/cmsis/inc +INC += -I$(TOP)/lib/oofatfs INC += -I$(TOP)/lib/tinyusb/hw INC += -I$(TOP)/lib/tinyusb/hw/bsp/teensy_40 +INC += -I$(TOP)/lib/tinyusb/src CFLAGS_MCU = -mtune=cortex-m7 -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 CFLAGS += $(INC) -Wall -Werror -Wdouble-promotion -Wfloat-conversion -std=c99 -nostdlib -mthumb $(CFLAGS_MCU) -CFLAGS += -DCPU_$(MCU_SERIES) -DCPU_$(MCU_VARIANT) +CFLAGS += -DCPU_$(MCU_SERIES) -DCPU_$(MCU_VARIANT) -DBOARD_$(BOARD) CFLAGS += -DXIP_EXTERNAL_FLASH=1 \ -DXIP_BOOT_HEADER_ENABLE=1 \ + -DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 \ -DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX \ -D__STARTUP_CLEAR_BSS \ -D__STARTUP_INITIALIZE_RAMFUNCTION \ -D__START=main \ - -DCPU_HEADER_H='<$(MCU_SERIES).h>' + -DCPU_HEADER_H='<$(MCU_SERIES).h>' \ + -DBOARD_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \ + -DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \ + +ifeq ($(MICROPY_HW_FLASH_TYPE), qspi_nor) +CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_nor_flash.h\" +else ifeq ($(MICROPY_HW_FLASH_TYPE), hyperflash) +CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_hyper_flash.h\" +endif + +ifeq ($(MICROPY_PY_MACHINE_SDCARD),1) +CFLAGS += -DMICROPY_PY_MACHINE_SDCARD=1 +endif + CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA) # Configure floating point support @@ -82,12 +118,13 @@ endif SUPPORTS_HARDWARE_FP_SINGLE = 0 SUPPORTS_HARDWARE_FP_DOUBLE = 0 -LDFLAGS = $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref --print-memory-usage +LDFLAGS = -Map=$@.map --cref --print-memory-usage +LDDEFINES = $(addprefix -D, $(LD_MEMORY_CONFIG_DEFINES)) LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) # Tune for Debugging or Optimization ifeq ($(DEBUG),1) -CFLAGS += -O0 -ggdb +CFLAGS += -Og -ggdb LDFLAGS += --gc-sections CFLAGS += -fdata-sections -ffunction-sections else @@ -96,68 +133,131 @@ LDFLAGS += --gc-sections CFLAGS += -fdata-sections -ffunction-sections endif +# All settings for Ethernet support are controller by the value of MICROPY_PY_LWIP +ifeq ($(MICROPY_PY_LWIP), 1) + +INC += -Ilwip_inc +INC += -Ihal/phy + +SRC_MOD := $(filter-out %/mbedtls/library/error.c, $(SRC_MOD)) + +SRC_ETH_C += \ + hal/phy/mdio/enet/fsl_enet_mdio.c \ + hal/phy/device/phydp83825/fsl_phydp83825.c \ + hal/phy/device/phydp83848/fsl_phydp83848.c \ + hal/phy/device/phyksz8081/fsl_phyksz8081.c \ + hal/phy/device/phylan8720/fsl_phylan8720.c \ + lib/mbedtls_errors/mp_mbedtls_errors.c \ + $(MCU_DIR)/drivers/fsl_enet.c \ + +SRC_QSTR += \ + extmod/modlwip.c \ + extmod/modnetwork.c \ + extmod/moduwebsocket.c \ + extmod/modusocket.c \ + network_lan.c \ + +CFLAGS += -DFSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE=1 \ + -DMBEDTLS_CONFIG_FILE='"mbedtls/mbedtls_config.h"' + +endif + # TinyUSB Stack source SRC_TINYUSB_C += \ - lib/tinyusb/src/tusb.c \ - lib/tinyusb/src/common/tusb_fifo.c \ - lib/tinyusb/src/device/usbd.c \ - lib/tinyusb/src/device/usbd_control.c \ - lib/tinyusb/src/class/msc/msc_device.c \ lib/tinyusb/src/class/cdc/cdc_device.c \ lib/tinyusb/src/class/dfu/dfu_rt_device.c \ lib/tinyusb/src/class/hid/hid_device.c \ lib/tinyusb/src/class/midi/midi_device.c \ + lib/tinyusb/src/class/msc/msc_device.c \ lib/tinyusb/src/class/usbtmc/usbtmc_device.c \ lib/tinyusb/src/class/vendor/vendor_device.c \ - lib/tinyusb/src/portable/nxp/transdimension/dcd_transdimension.c + lib/tinyusb/src/common/tusb_fifo.c \ + lib/tinyusb/src/device/usbd.c \ + lib/tinyusb/src/device/usbd_control.c \ + lib/tinyusb/src/portable/nxp/transdimension/dcd_transdimension.c \ + lib/tinyusb/src/tusb.c SRC_HAL_IMX_C += \ - $(MCU_DIR)/system_$(MCU_SERIES).c \ - $(MCU_DIR)/xip/fsl_flexspi_nor_boot.c \ - $(MCU_DIR)/project_template/clock_config.c \ $(MCU_DIR)/drivers/fsl_adc.c \ $(MCU_DIR)/drivers/fsl_cache.c \ $(MCU_DIR)/drivers/fsl_clock.c \ + $(MCU_DIR)/drivers/fsl_common.c \ $(MCU_DIR)/drivers/fsl_dmamux.c \ $(MCU_DIR)/drivers/fsl_edma.c \ + $(MCU_DIR)/drivers/fsl_flexram.c \ + $(MCU_DIR)/drivers/fsl_flexspi.c \ $(MCU_DIR)/drivers/fsl_gpio.c \ $(MCU_DIR)/drivers/fsl_gpt.c \ - $(MCU_DIR)/drivers/fsl_common.c \ $(MCU_DIR)/drivers/fsl_lpi2c.c \ $(MCU_DIR)/drivers/fsl_lpspi.c \ $(MCU_DIR)/drivers/fsl_lpspi_edma.c \ $(MCU_DIR)/drivers/fsl_lpuart.c \ - $(MCU_DIR)/drivers/fsl_flexram.c \ - $(MCU_DIR)/drivers/fsl_flexspi.c \ + $(MCU_DIR)/drivers/fsl_ocotp.c \ $(MCU_DIR)/drivers/fsl_pit.c \ + $(MCU_DIR)/drivers/fsl_pwm.c \ $(MCU_DIR)/drivers/fsl_snvs_lp.c \ $(MCU_DIR)/drivers/fsl_trng.c \ + $(MCU_DIR)/drivers/fsl_wdog.c \ + $(MCU_DIR)/project_template/clock_config.c \ + $(MCU_DIR)/system_$(MCU_SERIES).c \ + $(MCU_DIR)/xip/fsl_flexspi_nor_boot.c \ + +ifeq ($(MICROPY_HW_SDRAM_AVAIL), 1) +SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_semc.c +endif + +ifeq ($(MICROPY_PY_MACHINE_SDCARD),1) +SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_usdhc.c +endif + +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES), MIMXRT1015 MIMXRT1021 MIMXRT1052 MIMXRT1062 MIMXRT1064)) +SRC_HAL_IMX_C += \ + $(MCU_DIR)/drivers/fsl_qtmr.c +endif SRC_C += \ - main.c \ - led.c \ - pin.c \ - ticks.c \ - tusb_port.c \ board_init.c \ dma_channel.c \ - $(BOARD_DIR)/flash_config.c \ + drivers/bus/softspi.c \ + drivers/dht/dht.c \ + eth.c \ + extmod/modnetwork.c \ + extmod/modonewire.c \ + extmod/modusocket.c \ + extmod/uos_dupterm.c \ + fatfs_port.c \ + hal/pwm_backport.c \ + led.c \ machine_adc.c \ + machine_bitstream.c \ machine_i2c.c \ machine_led.c \ machine_pin.c \ machine_rtc.c \ + machine_sdcard.c \ machine_spi.c \ machine_timer.c \ machine_uart.c \ + machine_wdt.c \ + main.c \ + mbedtls/mbedtls_port.c \ mimxrt_flash.c \ - modutime.c \ + mimxrt_sdram.c \ modmachine.c \ modmimxrt.c \ moduos.c \ + modutime.c \ mphalport.c \ + mpnetworkport.c \ + network_lan.c \ + pendsv.c \ + pin.c \ + sdcard.c \ shared/libc/printf.c \ shared/libc/string0.c \ + shared/netutils/netutils.c \ + shared/netutils/trace.c \ + shared/netutils/dhcpserver.c \ shared/readline/readline.c \ shared/runtime/gchelper_native.c \ shared/runtime/mpirq.c \ @@ -165,10 +265,25 @@ SRC_C += \ shared/runtime/stdout_helpers.c \ shared/runtime/sys_stdio_mphal.c \ shared/timeutils/timeutils.c \ - drivers/bus/softspi.c \ - extmod/modonewire.c \ + systick.c \ + ticks.c \ + tusb_port.c \ $(SRC_TINYUSB_C) \ $(SRC_HAL_IMX_C) \ + $(SRC_ETH_C) \ + + +ifeq ($(MICROPY_HW_FLASH_TYPE), qspi_nor) +SRC_C += \ + hal/flexspi_nor_flash.c \ + hal/qspi_nor_flash_config.c +else ifeq ($(MICROPY_HW_FLASH_TYPE), hyperflash) +SRC_C += \ + hal/flexspi_hyper_flash.c \ + hal/qspi_hyper_flash_config.c +else +$(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE)) +endif ifeq ($(MICROPY_FLOAT_IMPL),double) LIBM_SRC_C += $(addprefix lib/libm_dbl/,\ @@ -188,9 +303,9 @@ LIBM_SRC_C += $(addprefix lib/libm_dbl/,\ atan2.c \ atanh.c \ ceil.c \ + copysign.c \ cos.c \ cosh.c \ - copysign.c \ erf.c \ exp.c \ expm1.c \ @@ -222,7 +337,6 @@ LIBM_SRC_C += lib/libm_dbl/sqrt.c endif else LIBM_SRC_C += $(addprefix lib/libm/,\ - math.c \ acoshf.c \ asinfacosf.c \ asinhf.c \ @@ -237,6 +351,7 @@ LIBM_SRC_C += $(addprefix lib/libm/,\ kf_sin.c \ kf_tan.c \ log1pf.c \ + math.c \ nearbyintf.c \ roundf.c \ sf_cos.c \ @@ -263,28 +378,34 @@ ifeq ($(MICROPY_FLOAT_IMPL),double) $(LIBM_O): CFLAGS := $(filter-out -Wdouble-promotion -Wfloat-conversion, $(CFLAGS)) endif -SRC_SS = $(MCU_DIR)/gcc/startup_$(MCU_SERIES).S +SRC_SS = \ + $(MCU_DIR)/gcc/startup_$(MCU_SERIES).S \ + hal/resethandler_MIMXRT10xx.S -SRC_S = shared/runtime/gchelper_m3.s \ +SRC_S += shared/runtime/gchelper_m3.s \ # List of sources for qstr extraction SRC_QSTR += \ + extmod/modonewire.c \ + extmod/uos_dupterm.c \ machine_adc.c \ machine_led.c \ machine_pin.c \ + machine_pwm.c \ machine_rtc.c \ + machine_sdcard.c \ machine_spi.c \ machine_timer.c \ machine_uart.c \ + machine_wdt.c \ mimxrt_flash.c \ - modutime.c \ modmachine.c \ modmimxrt.c \ moduos.c \ + modutime.c \ pin.c \ shared/runtime/mpirq.c \ shared/runtime/sys_stdio_mphal.c \ - extmod/modonewire.c \ $(GEN_PINS_SRC) \ OBJ += $(PY_O) @@ -301,8 +422,10 @@ $(BUILD)/lib/tinyusb/src/device/usbd.o: CFLAGS += -Wno-missing-braces all: $(BUILD)/firmware.hex $(BUILD)/firmware.bin $(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "PREPROCESS LINK $@" + $(Q)$(CC) -E -x c $(LDDEFINES) $(LD_FILES) | grep -v '^#' > $(BUILD)/link.ld $(ECHO) "LINK $@" - $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(LD) -T$(BUILD)/link.ld $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ $(BUILD)/firmware.bin: $(BUILD)/firmware.elf @@ -311,22 +434,29 @@ $(BUILD)/firmware.bin: $(BUILD)/firmware.elf $(BUILD)/firmware.hex: $(BUILD)/firmware.elf $(Q)$(OBJCOPY) -O ihex -R .eeprom $< $@ -# Making OBJ use an order-only depenedency on the generated pins.h file +# Making OBJ use an order-only dependency on the generated pins.h file # has the side effect of making the pins.h file before we actually compile # any of the objects. The normal dependency generation will deal with the # case when pins.h is modified. But when it doesn't exist, we don't know # which source files might need it. -$(OBJ): | $(GEN_PINS_HDR) +$(OBJ): | $(GEN_PINS_HDR) $(GEN_FLEXRAM_CONFIG_SRC) # With conditional pins, we may need to regenerate qstrdefs.h when config # options change. $(HEADER_BUILD)/qstrdefs.generated.h: $(BOARD_DIR)/mpconfigboard.h +$(GEN_FLEXRAM_CONFIG_SRC): + $(ECHO) "Create $@" + $(Q)$(PYTHON) $(MAKE_FLEXRAM_LD) -d $(TOP)/$(MCU_DIR)/$(MCU_SERIES).h \ + -f $(TOP)/$(MCU_DIR)/$(MCU_SERIES)_features.h -l boards/$(MCU_SERIES).ld -c $(MCU_SERIES) > $(GEN_FLEXRAM_CONFIG_SRC) + + # Use a pattern rule here so that make will only call make-pins.py once to make # both pins_gen.c and pins.h $(BUILD)/%_gen.c $(HEADER_BUILD)/%.h: $(BOARD_PINS) $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) $(ECHO) "Create $@" $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE)\ + --iomux $(abspath $(TOP)/$(MCU_DIR)/drivers/fsl_iomuxc.h) \ --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) > $(GEN_PINS_SRC) $(BUILD)/pins_gen.o: $(BUILD)/pins_gen.c diff --git a/ports/mimxrt/README.md b/ports/mimxrt/README.md index c24939f47..c8c5d989b 100644 --- a/ports/mimxrt/README.md +++ b/ports/mimxrt/README.md @@ -1,17 +1,31 @@ Port of MicroPython to NXP iMX RT 10xx ====================================== -Currently supports Teensy 4.0 and the i.MX RT1010 EVK board. +Currently supports Teensy 4.0, Teensy 4.1, and the +MIMXRT1010_EVK, MIMXRT1020_EVK, MIMXRT1050_EVK, MIMXRT1060_EVK and +MIMXRT1064_EVK boards. Features: - REPL over USB VCP + - machine.ADC + - machine.I2C + - machine.LED - machine.Pin + - machine.PWM + - machine.RTC + - machine.SDCard + - machine.SPI + - machine.Signal + - machine.SoftI2C + - machine.SoftSPI + - machine.Timer + - machine.UART + - LFS2 file system at the internal Flash + - SDCard support (not on MIMXRT1010_EVK) + - Ethernet (not on Teensy 4.0 and MIMXRT1010_EVK) Known issues: - - pyboard.py doesn't work with files larger than 64 bytes - - machine.Pin class currently does not support GPIOMUX option of - i.MX RT101x variants TODO: - - Enable TCM - - Peripherals (LED, Timers, etc) + - More peripherals (Counter, I2S, CAN, etc) + - More Python options diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c index 65024ff3e..d96645fef 100644 --- a/ports/mimxrt/board_init.c +++ b/ports/mimxrt/board_init.c @@ -40,7 +40,6 @@ #include "clock_config.h" #include "modmachine.h" -volatile uint32_t systick_ms = 0; const uint8_t dcd_data[] = { 0x00 }; @@ -52,8 +51,15 @@ void board_init(void) { // Enable IOCON clock CLOCK_EnableClock(kCLOCK_Iomuxc); - // ------------- USB0 ------------- // + // ------------- SDRAM ------------ // + #ifdef MICROPY_HW_SDRAM_AVAIL + mimxrt_sdram_init(); + #endif + // 1ms tick timer + SysTick_Config(SystemCoreClock / 1000); + + // ------------- USB0 ------------- // // Clock CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U); CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U); @@ -85,6 +91,11 @@ void board_init(void) { // PIT machine_timer_init_PIT(); + + // SDCard + #if MICROPY_PY_MACHINE_SDCARD + machine_sdcard_init0(); + #endif } void USB_OTG1_IRQHandler(void) { diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK.ld b/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK.ld deleted file mode 100644 index 83da7ec73..000000000 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/MIMXRT1010_EVK.ld +++ /dev/null @@ -1 +0,0 @@ -flash_size = 16M; \ No newline at end of file diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/board.json b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json new file mode 100644 index 000000000..4bf9ce052 --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1010_EVK/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy_mimxrt.md" + ], + "docs": "", + "features": [ + "MicroUSB", + "Microphone", + "AudioCodec", + "SPDIF", + "OpenSDA", + "JLink" + ], + "images": [ + "i.MXRT1010-TOP.jpg" + ], + "mcu": "mimxrt", + "product": "MIMXRT1010_EVK", + "thumbnail": "", + "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1010-evaluation-kit:MIMXRT1010-EVK", + "vendor": "NXP" +} diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1010_EVK/clock_config.h new file mode 100644 index 000000000..76f3df422 --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1010_EVK/clock_config.h @@ -0,0 +1,104 @@ +/* + * Copyright 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */ +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockRUN configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 500000000U /*!< Core clock frequency: 500000000Hz */ + +/* Clock outputs (values are in Hz): */ +#define BOARD_BOOTCLOCKRUN_ADC_ALT_CLK 40000000UL +#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL +#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL +#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL +#define BOARD_BOOTCLOCKRUN_CORE_CLK_ROOT 500000000UL +#define BOARD_BOOTCLOCKRUN_ENET_500M_REF_CLK 500000000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 132000000UL +#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 62500000UL +#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 62500000UL +#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 125000000UL +#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL +#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL +#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL +#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 62500000UL +#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL +#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL +#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL +#define BOARD_BOOTCLOCKRUN_USBPHY_CLK 0UL + +/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN; +/*! @brief Sys PLL for BOARD_BootClockRUN configuration. + */ +extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN; +/*! @brief Enet PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_enet_pll_config_t enetPllConfig_BOARD_BootClockRUN; + +/******************************************************************************* + * API for BOARD_BootClockRUN configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockRUN(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/evkmimxrt1010_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1010_EVK/evkmimxrt1010_flexspi_nor_config.h deleted file mode 100644 index 2cb4535ed..000000000 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/evkmimxrt1010_flexspi_nor_config.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2019 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.h - -#ifndef __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__ -#define __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__ - -#include -#include -#include "fsl_common.h" - -/*! @name Driver version */ -/*@{*/ -/*! @brief XIP_BOARD driver version 2.0.0. */ -#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) -/*@}*/ - -/* FLEXSPI memory config block related defintions */ -#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian -#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 -#define FLEXSPI_CFG_BLK_SIZE (512) - -/* FLEXSPI Feature related definitions */ -#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 - -/* Lookup table related defintions */ -#define CMD_INDEX_READ 0 -#define CMD_INDEX_READSTATUS 1 -#define CMD_INDEX_WRITEENABLE 2 -#define CMD_INDEX_WRITE 4 - -#define CMD_LUT_SEQ_IDX_READ 0 -#define CMD_LUT_SEQ_IDX_READSTATUS 1 -#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define CMD_LUT_SEQ_IDX_WRITE 9 - -#define CMD_SDR 0x01 -#define CMD_DDR 0x21 -#define RADDR_SDR 0x02 -#define RADDR_DDR 0x22 -#define CADDR_SDR 0x03 -#define CADDR_DDR 0x23 -#define MODE1_SDR 0x04 -#define MODE1_DDR 0x24 -#define MODE2_SDR 0x05 -#define MODE2_DDR 0x25 -#define MODE4_SDR 0x06 -#define MODE4_DDR 0x26 -#define MODE8_SDR 0x07 -#define MODE8_DDR 0x27 -#define WRITE_SDR 0x08 -#define WRITE_DDR 0x28 -#define READ_SDR 0x09 -#define READ_DDR 0x29 -#define LEARN_SDR 0x0A -#define LEARN_DDR 0x2A -#define DATSZ_SDR 0x0B -#define DATSZ_DDR 0x2B -#define DUMMY_SDR 0x0C -#define DUMMY_DDR 0x2C -#define DUMMY_RWDS_SDR 0x0D -#define DUMMY_RWDS_DDR 0x2D -#define JMP_ON_CS 0x1F -#define STOP 0 - -#define FLEXSPI_1PAD 0 -#define FLEXSPI_2PAD 1 -#define FLEXSPI_4PAD 2 -#define FLEXSPI_8PAD 3 - -#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ - (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ - FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) - -//!@brief Definitions for FlexSPI Serial Clock Frequency -typedef enum _FlexSpiSerialClockFreq -{ - kFlexSpiSerialClk_30MHz = 1, - kFlexSpiSerialClk_50MHz = 2, - kFlexSpiSerialClk_60MHz = 3, - kFlexSpiSerialClk_75MHz = 4, - kFlexSpiSerialClk_80MHz = 5, - kFlexSpiSerialClk_100MHz = 6, - kFlexSpiSerialClk_120MHz = 7, - kFlexSpiSerialClk_133MHz = 8, -} flexspi_serial_clk_freq_t; - -//!@brief FlexSPI clock configuration type -enum -{ - kFlexSpiClk_SDR, //!< Clock configure for SDR mode - kFlexSpiClk_DDR, //!< Clock configurat for DDR mode -}; - -//!@brief FlexSPI Read Sample Clock Source definition -typedef enum _FlashReadSampleClkSource -{ - kFlexSPIReadSampleClk_LoopbackInternally = 0, - kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, - kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, - kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, -} flexspi_read_sample_clk_t; - -//!@brief Misc feature bit definitions -enum -{ - kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable - kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable - kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable - kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable - kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable - kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable - kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. -}; - -//!@brief Flash Type Definition -enum -{ - kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR - kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND - kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH - kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND - kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs -}; - -//!@brief Flash Pad Definitions -enum -{ - kSerialFlash_1Pad = 1, - kSerialFlash_2Pads = 2, - kSerialFlash_4Pads = 4, - kSerialFlash_8Pads = 8, -}; - -//!@brief FlexSPI LUT Sequence structure -typedef struct _lut_sequence -{ - uint8_t seqNum; //!< Sequence Number, valid number: 1-16 - uint8_t seqId; //!< Sequence Index, valid number: 0-15 - uint16_t reserved; -} flexspi_lut_seq_t; - -//!@brief Flash Configuration Command Type -enum -{ - kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc - kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command - kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode - kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode - kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode - kDeviceConfigCmdType_Reset, //!< Reset device command -}; - -//!@brief FlexSPI Memory Configuration Block -typedef struct _FlexSPIConfig -{ - uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL - uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix - uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use - uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 - uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 - uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 - uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For - //! Serial NAND, need to refer to datasheet - uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable - uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, - //! Generic configuration, etc. - uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for - //! DPI/QPI/OPI switch or reset command - flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt - //! sequence number, [31:16] Reserved - uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration - uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable - uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe - flexspi_lut_seq_t - configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq - uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use - uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands - uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use - uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more - //! details - uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details - uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal - uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot - //! Chapter for more details - uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot - //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH - uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use - uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 - uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 - uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 - uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 - uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value - uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value - uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value - uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value - uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command - uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands - uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns - uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 - uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - - //! busy flag is 0 when flash device is busy - uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences - flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences - uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use -} flexspi_mem_config_t; - -/* */ -#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 -#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 -#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 -#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 -#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 -#define NOR_CMD_LUT_SEQ_IDX_READID 8 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 -#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 -#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 -#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 - -/* - * Serial NOR configuration block - */ -typedef struct _flexspi_nor_config -{ - flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI - uint32_t pageSize; //!< Page size of Serial NOR - uint32_t sectorSize; //!< Sector size of Serial NOR - uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command - uint8_t isUniformBlockSize; //!< Sector/Block size is the same - uint8_t reserved0[2]; //!< Reserved for future use - uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 - uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command - uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false - uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution - uint32_t blockSize; //!< Block size - uint32_t reserve2[11]; //!< Reserved for future use -} flexspi_nor_config_t; - -#define FLASH_BUSY_STATUS_POL 0 -#define FLASH_BUSY_STATUS_OFFSET 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif -#endif /* __EVKMIMXRT1011_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1010_EVK/flash_config.c deleted file mode 100644 index 5e7e5dcf1..000000000 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/flash_config.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2019 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c - -#include "evkmimxrt1010_flexspi_nor_config.h" - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.xip_board" -#endif - -/******************************************************************************* - * Code - ******************************************************************************/ -#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) -#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) -__attribute__((section(".boot_hdr.conf"))) -#elif defined(__ICCARM__) -#pragma location = ".boot_hdr.conf" -#endif - -const flexspi_nor_config_t qspiflash_config = { - .memConfig = - { - .tag = FLEXSPI_CFG_BLK_TAG, - .version = FLEXSPI_CFG_BLK_VERSION, - .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad, - .csHoldTime = 3u, - .csSetupTime = 3u, - .sflashPadType = kSerialFlash_4Pads, - .serialClkFreq = kFlexSpiSerialClk_100MHz, - .sflashA1Size = 16u * 1024u * 1024u, - .lookupTable = - { - // 0 Read LUTs 0 -> 0 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 1 Read status register -> 1 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 2 Fast read quad mode - SDR - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 3 Write Enable -> 3 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 4 Read extend parameters - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 5 Erase Sector -> 5 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 6 Write Status Reg - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 7 Page Program - quad mode (-> 9) - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 8 Read ID - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 9 Page Program - single mode -> 9 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 10 Enter QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 11 Erase Chip - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 12 Exit QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - }, - }, - .pageSize = 256u, - .sectorSize = 4u * 1024u, - .blockSize = 256u * 1024u, - .isUniformBlockSize = false, -}; -#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h index 2cdb433e1..9a74a1c9c 100644 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h @@ -1,29 +1,26 @@ #define MICROPY_HW_BOARD_NAME "i.MX RT1010 EVK" #define MICROPY_HW_MCU_NAME "MIMXRT1011DAE5A" -#define BOARD_FLASH_SIZE (16 * 1024 * 1024) - // i.MX RT1010 EVK has 1 board LED #define MICROPY_HW_LED1_PIN (pin_GPIO_11) #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) -#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1010_flexspi_nor_config.h" -#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h" #define MICROPY_HW_NUM_PIN_IRQS (2 * 32) // Define mapping logical UART # to hardware UART # -// LPUART1 on D0/D1 -> 1 -// LPUART3 on A0/D4 -> 3 -// LPUART4 on D6/D7 -> 2 +// LPUART1 on USB_DBG -> 0 +// LPUART1 on D0/D1 -> 1 +// LPUART3 on A0/D4 -> 3 +// LPUART4 on D6/D7 -> 2 #define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) -#define MICROPY_HW_UART_INDEX { 0, 1, 4, 3 } +#define MICROPY_HW_UART_INDEX { 1, 1, 4, 3 } #define IOMUX_TABLE_UART \ { IOMUXC_GPIO_10_LPUART1_TXD }, { IOMUXC_GPIO_09_LPUART1_RXD }, \ { 0 }, { 0 }, \ - { IOMUXC_GPIO_08_LPUART3_TXD }, { IOMUXC_GPIO_AD_07_LPUART3_RXD }, \ + { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_02_LPUART4_TXD }, { IOMUXC_GPIO_AD_01_LPUART4_RXD }, #define MICROPY_HW_SPI_INDEX { 1 } @@ -33,7 +30,7 @@ { IOMUXC_GPIO_AD_04_LPSPI1_SDO }, { IOMUXC_GPIO_AD_03_LPSPI1_SDI }, #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx } -#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx } +#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx } // Define mapping hardware I2C # to logical I2C # // SDA/SCL HW-I2C Logical I2C diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk index ccc8ffeb4..c2a50d722 100644 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.mk @@ -2,21 +2,19 @@ MCU_SERIES = MIMXRT1011 MCU_VARIANT = MIMXRT1011DAE5A MICROPY_FLOAT_IMPL = single +MICROPY_PY_MACHINE_SDCARD = 0 +MICROPY_HW_FLASH_TYPE ?= qspi_nor +MICROPY_HW_FLASH_SIZE ?= 0x1000000 # 16MB -SRC_C += \ - hal/flexspi_nor_flash.c \ - -JLINK_PATH = /media/RT1010-EVK/ +JLINK_PATH ?= /media/RT1010-EVK/ JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink - ifdef JLINK_IP JLINK_CONNECTION_SETTINGS = -IP $(JLINK_IP) else JLINK_CONNECTION_SETTINGS = -USB endif - deploy_jlink: $(BUILD)/firmware.hex $(Q)$(TOUCH) $(JLINK_COMMANDER_SCRIPT) $(ECHO) "ExitOnError 1" > $(JLINK_COMMANDER_SCRIPT) diff --git a/ports/mimxrt/boards/MIMXRT1011.ld b/ports/mimxrt/boards/MIMXRT1011.ld index d9a495685..19bbc2770 100644 --- a/ports/mimxrt/boards/MIMXRT1011.ld +++ b/ports/mimxrt/boards/MIMXRT1011.ld @@ -1,15 +1,24 @@ /* Memory configuration */ +#if MICROPY_HW_FLASH_RESERVED +reserved_size = MICROPY_HW_FLASH_RESERVED; +#endif + +#if MICROPY_HW_FLASH_TYPE==qspi_nor flash_start = 0x60000000; +#else +#error Unknown MICROPY_HW_FLASH_TYPE +#endif +flash_size = MICROPY_HW_FLASH_SIZE; flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); -flash_config_start = 0x60000400; +flash_config_start = flash_start + 0x00000400; flash_config_size = 0x00000C00; -ivt_start = 0x60001000; +ivt_start = flash_start + 0x00001000; ivt_size = 0x00001000; -interrupts_start = 0x60002000; +interrupts_start = flash_start + 0x00002000; interrupts_size = 0x00000400; -text_start = 0x60002400; -text_size = ((((text_start) + 1M) + (4k - 1)) & ~(4k - 1)) - (text_start); /* reserve 1M for code but align on 4k boundary */ -vfs_start = (text_start) + (text_size); +text_start = flash_start + 0x00002400; +vfs_start = flash_start + 0x00100000; +text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); itcm_start = 0x00000000; itcm_size = 0x00008000; diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK.ld b/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK.ld deleted file mode 100644 index fd1bf32ed..000000000 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/MIMXRT1020_EVK.ld +++ /dev/null @@ -1 +0,0 @@ -flash_size = 8M; \ No newline at end of file diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/board.json b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json new file mode 100644 index 000000000..cc74c25fe --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1020_EVK/board.json @@ -0,0 +1,25 @@ +{ + "deploy": [ + "../deploy_mimxrt.md" + ], + "docs": "", + "features": [ + "Ethernet", + "SDRAM", + "MicroSD", + "MicroUSB", + "Microphone", + "AudioCodec", + "CAN", + "OpenSDA", + "JLink" + ], + "images": [ + "MIMXRT-1020-EVKBD.jpg" + ], + "mcu": "mimxrt", + "product": "MIMXRT1020_EVK", + "thumbnail": "", + "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1020-evaluation-kit:MIMXRT1020-EVK", + "vendor": "NXP" +} diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1020_EVK/clock_config.h new file mode 100644 index 000000000..21d4e630a --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1020_EVK/clock_config.h @@ -0,0 +1,114 @@ +/* + * Copyright 2018-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */ +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockRUN configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 500000000U /*!< Core clock frequency: 500000000Hz */ + +/* Clock outputs (values are in Hz): */ +#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 500000000UL +#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL +#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL +#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL +#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL +#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 0UL +#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 0UL +#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 0UL +#define BOARD_BOOTCLOCKRUN_ENET_500M_REF_CLK 500000000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 132000000UL +#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 62500000UL +#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 62500000UL +#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 125000000UL +#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL +#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL +#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL +#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 62500000UL +#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 62500000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL +#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL +#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL +#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 176000000UL +#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 176000000UL + +/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN; +/*! @brief Sys PLL for BOARD_BootClockRUN configuration. + */ +extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN; +/*! @brief Enet PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_enet_pll_config_t enetPllConfig_BOARD_BootClockRUN; + +/******************************************************************************* + * API for BOARD_BootClockRUN configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockRUN(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/evkmimxrt1020_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1020_EVK/evkmimxrt1020_flexspi_nor_config.h deleted file mode 100644 index 195c0c225..000000000 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/evkmimxrt1020_flexspi_nor_config.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2019 NXP. - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1020_flexspi_nor_config.h - -#ifndef __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__ -#define __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__ - -#include -#include -#include "fsl_common.h" - -/*! @name Driver version */ -/*@{*/ -/*! @brief XIP_BOARD driver version 2.0.0. */ -#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) -/*@}*/ - -/* FLEXSPI memory config block related defintions */ -#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian -#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 -#define FLEXSPI_CFG_BLK_SIZE (512) - -/* FLEXSPI Feature related definitions */ -#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 - -/* Lookup table related defintions */ -#define CMD_INDEX_READ 0 -#define CMD_INDEX_READSTATUS 1 -#define CMD_INDEX_WRITEENABLE 2 -#define CMD_INDEX_WRITE 4 - -#define CMD_LUT_SEQ_IDX_READ 0 -#define CMD_LUT_SEQ_IDX_READSTATUS 1 -#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define CMD_LUT_SEQ_IDX_WRITE 9 - -#define CMD_SDR 0x01 -#define CMD_DDR 0x21 -#define RADDR_SDR 0x02 -#define RADDR_DDR 0x22 -#define CADDR_SDR 0x03 -#define CADDR_DDR 0x23 -#define MODE1_SDR 0x04 -#define MODE1_DDR 0x24 -#define MODE2_SDR 0x05 -#define MODE2_DDR 0x25 -#define MODE4_SDR 0x06 -#define MODE4_DDR 0x26 -#define MODE8_SDR 0x07 -#define MODE8_DDR 0x27 -#define WRITE_SDR 0x08 -#define WRITE_DDR 0x28 -#define READ_SDR 0x09 -#define READ_DDR 0x29 -#define LEARN_SDR 0x0A -#define LEARN_DDR 0x2A -#define DATSZ_SDR 0x0B -#define DATSZ_DDR 0x2B -#define DUMMY_SDR 0x0C -#define DUMMY_DDR 0x2C -#define DUMMY_RWDS_SDR 0x0D -#define DUMMY_RWDS_DDR 0x2D -#define JMP_ON_CS 0x1F -#define STOP 0 - -#define FLEXSPI_1PAD 0 -#define FLEXSPI_2PAD 1 -#define FLEXSPI_4PAD 2 -#define FLEXSPI_8PAD 3 - -#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ - (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ - FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) - -//!@brief Definitions for FlexSPI Serial Clock Frequency -typedef enum _FlexSpiSerialClockFreq -{ - kFlexSpiSerialClk_30MHz = 1, - kFlexSpiSerialClk_50MHz = 2, - kFlexSpiSerialClk_60MHz = 3, - kFlexSpiSerialClk_75MHz = 4, - kFlexSpiSerialClk_80MHz = 5, - kFlexSpiSerialClk_100MHz = 6, - kFlexSpiSerialClk_133MHz = 7, - kFlexSpiSerialClk_166MHz = 8, - kFlexSpiSerialClk_200MHz = 9, -} flexspi_serial_clk_freq_t; - -//!@brief FlexSPI clock configuration type -enum -{ - kFlexSpiClk_SDR, //!< Clock configure for SDR mode - kFlexSpiClk_DDR, //!< Clock configurat for DDR mode -}; - -//!@brief FlexSPI Read Sample Clock Source definition -typedef enum _FlashReadSampleClkSource -{ - kFlexSPIReadSampleClk_LoopbackInternally = 0, - kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, - kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, - kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, -} flexspi_read_sample_clk_t; - -//!@brief Misc feature bit definitions -enum -{ - kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable - kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable - kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable - kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable - kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable - kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable - kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. -}; - -//!@brief Flash Type Definition -enum -{ - kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR - kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND - kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH - kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND - kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs -}; - -//!@brief Flash Pad Definitions -enum -{ - kSerialFlash_1Pad = 1, - kSerialFlash_2Pads = 2, - kSerialFlash_4Pads = 4, - kSerialFlash_8Pads = 8, -}; - -//!@brief FlexSPI LUT Sequence structure -typedef struct _lut_sequence -{ - uint8_t seqNum; //!< Sequence Number, valid number: 1-16 - uint8_t seqId; //!< Sequence Index, valid number: 0-15 - uint16_t reserved; -} flexspi_lut_seq_t; - -//!@brief Flash Configuration Command Type -enum -{ - kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc - kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command - kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode - kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode - kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode - kDeviceConfigCmdType_Reset, //!< Reset device command -}; - -//!@brief FlexSPI Memory Configuration Block -typedef struct _FlexSPIConfig -{ - uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL - uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix - uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use - uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 - uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 - uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 - uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For - //! Serial NAND, need to refer to datasheet - uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable - uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, - //! Generic configuration, etc. - uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for - //! DPI/QPI/OPI switch or reset command - flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt - //! sequence number, [31:16] Reserved - uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration - uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable - uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe - flexspi_lut_seq_t - configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq - uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use - uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands - uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use - uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more - //! details - uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details - uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal - uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot - //! Chapter for more details - uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot - //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH - uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use - uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 - uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 - uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 - uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 - uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value - uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value - uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value - uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value - uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command - uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands - uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns - uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 - uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - - //! busy flag is 0 when flash device is busy - uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences - flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences - uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use -} flexspi_mem_config_t; - -/* */ -#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 -#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 -#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 -#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 -#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 -#define NOR_CMD_LUT_SEQ_IDX_READID 8 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 -#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 -#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 -#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 - -/* - * Serial NOR configuration block - */ -typedef struct _flexspi_nor_config -{ - flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI - uint32_t pageSize; //!< Page size of Serial NOR - uint32_t sectorSize; //!< Sector size of Serial NOR - uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command - uint8_t isUniformBlockSize; //!< Sector/Block size is the same - uint8_t reserved0[2]; //!< Reserved for future use - uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 - uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command - uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false - uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution - uint32_t blockSize; //!< Block size - uint32_t reserve2[11]; //!< Reserved for future use -} flexspi_nor_config_t; - -#define FLASH_BUSY_STATUS_POL 0 -#define FLASH_BUSY_STATUS_OFFSET 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif -#endif /* __EVKMIMXRT1020_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1020_EVK/flash_config.c deleted file mode 100644 index 5377cc1b2..000000000 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/flash_config.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2019 NXP. - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c - -#include "evkmimxrt1020_flexspi_nor_config.h" - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.xip_board" -#endif - -/******************************************************************************* - * Code - ******************************************************************************/ -#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) -#if defined(__ARMCC_VERSION) || defined(__GNUC__) -__attribute__((section(".boot_hdr.conf"))) -#elif defined(__ICCARM__) -#pragma location = ".boot_hdr.conf" -#endif - -const flexspi_nor_config_t qspiflash_config = { - .memConfig = - { - .tag = FLEXSPI_CFG_BLK_TAG, - .version = FLEXSPI_CFG_BLK_VERSION, - .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad, - .csHoldTime = 3u, - .csSetupTime = 3u, - .busyOffset = FLASH_BUSY_STATUS_OFFSET, // Status bit 0 indicates busy. - .busyBitPolarity = FLASH_BUSY_STATUS_POL, // Busy when the bit is 1. - .deviceModeCfgEnable = 1u, - .deviceModeType = kDeviceConfigCmdType_QuadEnable, - .deviceModeSeq = { - .seqId = 4u, - .seqNum = 1u, - }, - .deviceModeArg = 0x40, - // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock - .deviceType = kFlexSpiDeviceType_SerialNOR, - .sflashPadType = kSerialFlash_4Pads, - .serialClkFreq = kFlexSpiSerialClk_30MHz, - .sflashA1Size = 8u * 1024u * 1024u, - .lookupTable = - { - // 0 Read LUTs 0 -> 0 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 1 Read status register -> 1 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 2 Fast read quad mode - SDR - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 3 Write Enable -> 3 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 4 Read extend parameters - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 5 Erase Sector -> 5 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 6 Write Status Reg - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 7 Page Program - quad mode (-> 9) - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 8 Read ID - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 9 Page Program - single mode -> 9 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 10 Enter QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 11 Erase Chip - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 12 Exit QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - }, - }, - .pageSize = 256u, - .sectorSize = 4u * 1024u, - .blockSize = 256u * 1024u, - .isUniformBlockSize = false, - .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz, -}; -#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h index d2a2cbbdb..5f5de5a3e 100644 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h @@ -1,29 +1,26 @@ #define MICROPY_HW_BOARD_NAME "i.MX RT1020 EVK" #define MICROPY_HW_MCU_NAME "MIMXRT1021DAG5A" -#define BOARD_FLASH_SIZE (8 * 1024 * 1024) - // i.MX RT1020 EVK has 1 board LED // Todo: think about replacing the define with searching in the generated pins? #define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_05) #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) -#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1020_flexspi_nor_config.h" -#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h" #define MICROPY_HW_NUM_PIN_IRQS (3 * 32) // Define mapping logical UART # to hardware UART # -// RX/TX HW-UART Logical UART -// D3/D5 LPUART1 Not usable, Since D3 is blocked. -// D0/D1 LPUART2 -> 1 -// D6/D9 LPUART3 -> 2 -// D10/D12 LPUART5 -> 3 -// D14/D15 LPUART8 -> 4 -// A0/A1 LPUART4 -> 5 +// RX/TX HW-UART Logical UART +// DEBUG USB LPUART1 -> 0 +// D3/D5 LPUART1 Not usable, Since D3 is blocked. +// D0/D1 LPUART2 -> 1 +// D6/D9 LPUART3 -> 2 +// D10/D12 LPUART5 -> 3 +// D14/D15 LPUART8 -> 4 +// A0/A1 LPUART4 -> 5 #define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) -#define MICROPY_HW_UART_INDEX { 0, 2, 3, 5, 8, 4 } +#define MICROPY_HW_UART_INDEX { 1, 2, 3, 5, 8, 4 } #define IOMUX_TABLE_UART \ { IOMUXC_GPIO_AD_B0_06_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_07_LPUART1_RX }, \ @@ -43,13 +40,13 @@ { 0 }, { 0 }, \ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_12_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B1_13_LPSPI3_PCS0 }, \ - { IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_15_LPSPI3_SDI }, + { IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_15_LPSPI3_SDI }, #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \ - kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } + kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ - kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } // Define mapping hardware I2C # to logical I2C # // SDA/SCL HW-I2C Logical I2C @@ -64,3 +61,81 @@ { IOMUXC_GPIO_AD_B1_08_LPI2C2_SCL }, { IOMUXC_GPIO_AD_B1_09_LPI2C2_SDA }, \ { 0 }, { 0 }, \ { IOMUXC_GPIO_SD_B1_02_LPI2C4_SCL }, { IOMUXC_GPIO_SD_B1_03_LPI2C4_SDA }, + +#define USDHC_DUMMY_PIN NULL, 0 +#define MICROPY_USDHC1 \ + { \ + .cmd = {GPIO_SD_B0_02_USDHC1_CMD}, \ + .clk = { GPIO_SD_B0_03_USDHC1_CLK }, \ + .cd_b = { GPIO_SD_B0_06_USDHC1_CD_B }, \ + .data0 = { GPIO_SD_B0_04_USDHC1_DATA0 }, \ + .data1 = { GPIO_SD_B0_05_USDHC1_DATA1 }, \ + .data2 = { GPIO_SD_B0_00_USDHC1_DATA2 }, \ + .data3 = { GPIO_SD_B0_01_USDHC1_DATA3 }, \ + } + +// --- SEMC --- // +#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00 +#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01 +#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02 +#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03 +#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04 +#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05 +#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06 +#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07 +#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_32_SEMC_DATA08 +#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_33_SEMC_DATA09 +#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_34_SEMC_DATA10 +#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_35_SEMC_DATA11 +#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_36_SEMC_DATA12 +#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_37_SEMC_DATA13 +#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_38_SEMC_DATA14 +#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_39_SEMC_DATA15 + +#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_16_SEMC_ADDR00 +#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_17_SEMC_ADDR01 +#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_18_SEMC_ADDR02 +#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_19_SEMC_ADDR03 +#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_20_SEMC_ADDR04 +#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_21_SEMC_ADDR05 +#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_22_SEMC_ADDR06 +#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_23_SEMC_ADDR07 +#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_24_SEMC_ADDR08 +#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_25_SEMC_ADDR09 +#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_15_SEMC_ADDR10 +#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_26_SEMC_ADDR11 +#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_27_SEMC_ADDR12 + +#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_13_SEMC_BA0 +#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_14_SEMC_BA1 +#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_10_SEMC_CAS +#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_29_SEMC_CKE +#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_30_SEMC_CLK +#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00 +#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_31_SEMC_DM01 +#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_28_SEMC_DQS +#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_11_SEMC_RAS +#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_09_SEMC_WE + +#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_12_SEMC_CS0 + +// Network definitions +// Transceiver Phy Address +#define ENET_PHY_ADDRESS (2) +#define ENET_PHY_OPS phyksz8081_ops + +// Etherner PIN definitions +#define ENET_RESET_PIN pin_GPIO_AD_B0_04 +#define ENET_INT_PIN pin_GPIO_AD_B1_06 + +#define IOMUX_TABLE_ENET \ + { IOMUXC_GPIO_AD_B0_08_ENET_REF_CLK1, 1, 0xB0E9u }, \ + { IOMUXC_GPIO_AD_B0_09_ENET_RDATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_AD_B0_10_ENET_RDATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_AD_B0_11_ENET_RX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_AD_B0_12_ENET_RX_ER, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_AD_B0_13_ENET_TX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_AD_B0_14_ENET_TDATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_AD_B0_15_ENET_TDATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_EMC_40_ENET_MDIO, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_EMC_41_ENET_MDC, 0, 0xB0E9u }, diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk index f8f66b0df..c1e1678e5 100644 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk @@ -2,22 +2,28 @@ MCU_SERIES = MIMXRT1021 MCU_VARIANT = MIMXRT1021DAG5A MICROPY_FLOAT_IMPL = double +MICROPY_PY_MACHINE_SDCARD = 1 +MICROPY_HW_FLASH_TYPE ?= qspi_nor +MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB -SRC_C += \ - hal/flexspi_nor_flash.c \ +MICROPY_HW_SDRAM_AVAIL = 1 +MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB + +MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 JLINK_PATH ?= /media/RT1020-EVK/ JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink - ifdef JLINK_IP JLINK_CONNECTION_SETTINGS = -IP $(JLINK_IP) else -JLINK_CONNECTION_SETTINGS = +JLINK_CONNECTION_SETTINGS = -USB endif - deploy_jlink: $(BUILD)/firmware.hex + $(Q)$(TOUCH) $(JLINK_COMMANDER_SCRIPT) $(ECHO) "ExitOnError 1" > $(JLINK_COMMANDER_SCRIPT) $(ECHO) "speed auto" >> $(JLINK_COMMANDER_SCRIPT) $(ECHO) "r" >> $(JLINK_COMMANDER_SCRIPT) diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld index de0f259dc..1263cd336 100644 --- a/ports/mimxrt/boards/MIMXRT1021.ld +++ b/ports/mimxrt/boards/MIMXRT1021.ld @@ -1,28 +1,48 @@ /* Memory configuration */ +#if defined MICROPY_HW_FLASH_RESERVED +reserved_size = MICROPY_HW_FLASH_RESERVED; +#endif + +#if MICROPY_HW_FLASH_TYPE == qspi_nor flash_start = 0x60000000; +#else +#error Unknown MICROPY_HW_FLASH_TYPE +#endif +flash_size = MICROPY_HW_FLASH_SIZE; flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); flash_config_start = flash_start; flash_config_size = 0x00001000; -ivt_start = 0x60001000; +ivt_start = flash_start + 0x00001000; ivt_size = 0x00001000; -interrupts_start = 0x60002000; +interrupts_start = flash_start + 0x00002000; interrupts_size = 0x00000400; -text_start = 0x60002400; -text_size = ((((text_start) + 1M) + (4k - 1)) & ~(4k - 1)) - (text_start); /* reserve 1M for code but align on 4k boundary */ -vfs_start = (text_start) + (text_size); +text_start = flash_start + 0x00002400; +vfs_start = flash_start + 0x00100000; +text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); itcm_start = 0x00000000; itcm_size = 0x00010000; dtcm_start = 0x20000000; -dtcm_size = 0x00010000; +dtcm_size = 0x00018000; ocrm_start = 0x20200000; -ocrm_size = 0x00020000; +ocrm_size = 0x00018000; + +#ifdef MICROPY_HW_SDRAM_AVAIL +sdram_start = 0x80000000; +sdram_size = MICROPY_HW_SDRAM_SIZE; +#endif /* 24kiB stack. */ __stack_size__ = 0x6000; _estack = __StackTop; _sstack = __StackLimit; +#ifdef MICROPY_HW_SDRAM_AVAIL +_gc_heap_start = ORIGIN(m_sdram); +_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); +#else /* Use second OCRAM bank for GC heap. */ +/* Use all OCRAM for the GC heap. */ _gc_heap_start = ORIGIN(m_ocrm); _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); +#endif diff --git a/ports/mimxrt/boards/MIMXRT1021_af.csv b/ports/mimxrt/boards/MIMXRT1021_af.csv index 668b415f0..3ce38eb0b 100644 --- a/ports/mimxrt/boards/MIMXRT1021_af.csv +++ b/ports/mimxrt/boards/MIMXRT1021_af.csv @@ -5,30 +5,30 @@ GPIO_AD_B0_02,JTAG_MOD,,,,,GPIO1_IO02,USBPHY1_TSTI_TX_LS_MODE,GPT1_CAPTURE1,,,,, GPIO_AD_B0_03,JTAG_TDI,USDHC2_CD_B,WDOG1_B,SAI1_MCLK,USDHC1_WP,GPIO1_IO03,USB_OTG1_OC,CCM_PMIC_RDY,,,,,ALT0 GPIO_AD_B0_04,JTAG_TDO,FLEXCAN1_TX,USDHC1_WP,TMR2_TIMER0,ENET_MDIO,GPIO1_IO04,USB_OTG1_PWR,EWM_OUT_B,,,,,ALT0 GPIO_AD_B0_05,JTAG_TRSTB,FLEXCAN1_RX,USDHC1_CD_B,TMR2_TIMER1,ENET_MDC,GPIO1_IO05,USB_OTG1_ID,ARM_NMI,,,,,ALT0 -GPIO_AD_B0_06,PIT_TRIGGER0,MQS_RIGHT,LPUART1_TXD,TMR2_TIMER2,FLEXPWM2_PWMA3,GPIO1_IO06,REF_32K_OUT,,,,,,ALT5 -GPIO_AD_B0_07,PIT_TRIGGER1,MQS_LEFT,LPUART1_RXD,TMR2_TIMER3,FLEXPWM2_PWMB3,GPIO1_IO07,REF_24M_OUT,,,,,,ALT5 +GPIO_AD_B0_06,PIT_TRIGGER0,MQS_RIGHT,LPUART1_TXD,TMR2_TIMER2,FLEXPWM2_PWM3_A,GPIO1_IO06,REF_32K_OUT,,,,,,ALT5 +GPIO_AD_B0_07,PIT_TRIGGER1,MQS_LEFT,LPUART1_RXD,TMR2_TIMER3,FLEXPWM2_PWM3_B,GPIO1_IO07,REF_24M_OUT,,,,,,ALT5 GPIO_AD_B0_08,ENET_TX_CLK,LPI2C3_SCL,LPUART1_CTS_B,KPP_COL0,ENET_REF_CLK,GPIO1_IO08,ARM_CM7_TXEV,,,,,ACMP1_IN4,ALT5 GPIO_AD_B0_09,ENET_RX_DATA1,LPI2C3_SDA,LPUART1_RTS_B,KPP_ROW0,,GPIO1_IO09,ARM_CM7_RXEV,,,,,ACMP2_IN4,ALT5 -GPIO_AD_B0_10,ENET_RX_DATA0,LPSPI1_SCK,LPUART5_TXD,KPP_COL1,FLEXPWM2_PWMA2,GPIO1_IO10,ARM_TRACE_CLK,,,,,ACMP3_IN4,ALT5 -GPIO_AD_B0_11,ENET_RX_EN,LPSPI1_PCS0,LPUART5_RXD,KPP_ROW1,FLEXPWM2_PWMB2,GPIO1_IO11,ARM_TRACE_SWO,,,,,ACMP4_IN4,ALT5 -GPIO_AD_B0_12,ENET_RX_ER,LPSPI1_SDO,LPUART3_CTS_B,KPP_COL2,FLEXPWM2_PWMA1,GPIO1_IO12,ARM_TRACE0,SNVS_VIO_5_CTL,,,ADC1_IN0,,ALT5 -GPIO_AD_B0_13,ENET_TX_EN,LPSPI1_SDI,LPUART3_RTS_B,KPP_ROW2,FLEXPWM2_PWMB1,GPIO1_IO13,,SNVS_VIO_5_B,,,ADC2_IN0,,ALT5 -GPIO_AD_B0_14,ENET_TX_DATA0,FLEXCAN2_TX,LPUART3_TXD,KPP_COL3,FLEXPWM2_PWMA0,GPIO1_IO14,,WDOG1_ANY,,,"ADC1_IN1,ADC2_IN1","ACMP1_IN0,ACMP2_IN0,ACMP3_IN0,ACMP4_IN0",ALT5 -GPIO_AD_B0_15,ENET_TX_DATA1,FLEXCAN2_RX,LPUART3_RXD,KPP_ROW3,FLEXPWM2_PWMB0,GPIO1_IO15,,,,,"ADC1_IN2,ADC2_IN2","ACMP1_IN1,ACMP2_IN1,ACMP3_IN1,ACMP4_IN1",ALT5 +GPIO_AD_B0_10,ENET_RX_DATA0,LPSPI1_SCK,LPUART5_TXD,KPP_COL1,FLEXPWM2_PWM2_A,GPIO1_IO10,ARM_TRACE_CLK,,,,,ACMP3_IN4,ALT5 +GPIO_AD_B0_11,ENET_RX_EN,LPSPI1_PCS0,LPUART5_RXD,KPP_ROW1,FLEXPWM2_PWM2_B,GPIO1_IO11,ARM_TRACE_SWO,,,,,ACMP4_IN4,ALT5 +GPIO_AD_B0_12,ENET_RX_ER,LPSPI1_SDO,LPUART3_CTS_B,KPP_COL2,FLEXPWM2_PWM1_A,GPIO1_IO12,ARM_TRACE0,SNVS_VIO_5_CTL,,,ADC1_IN0,,ALT5 +GPIO_AD_B0_13,ENET_TX_EN,LPSPI1_SDI,LPUART3_RTS_B,KPP_ROW2,FLEXPWM2_PWM1_B,GPIO1_IO13,,SNVS_VIO_5_B,,,ADC2_IN0,,ALT5 +GPIO_AD_B0_14,ENET_TX_DATA0,FLEXCAN2_TX,LPUART3_TXD,KPP_COL3,FLEXPWM2_PWM0_A,GPIO1_IO14,,WDOG1_ANY,,,"ADC1_IN1,ADC2_IN1","ACMP1_IN0,ACMP2_IN0,ACMP3_IN0,ACMP4_IN0",ALT5 +GPIO_AD_B0_15,ENET_TX_DATA1,FLEXCAN2_RX,LPUART3_RXD,KPP_ROW3,FLEXPWM2_PWM0_B,GPIO1_IO15,,,,,"ADC1_IN2,ADC2_IN2","ACMP1_IN1,ACMP2_IN1,ACMP3_IN1,ACMP4_IN1",ALT5 GPIO_AD_B1_00,SEMC_RDY,FLEXSPI_A_DATA3,FLEXCAN2_TX,SAI1_MCLK,FLEXIO1_D15,GPIO1_IO16,ENET_1588_EVENT2_OUT,KPP_COL4,,,,ACMP1_IN2,ALT5 GPIO_AD_B1_01,SEMC_CSX0,FLEXSPI_A_SCLK,FLEXCAN2_RX,SAI1_TX_BCLK,FLEXIO1_D14,GPIO1_IO17,ENET_1588_EVENT2_IN,KPP_ROW4,,,ADC1_IN3,ACMP2_IN2,ALT5 GPIO_AD_B1_02,SEMC_CSX1,FLEXSPI_A_DATA0,LPSPI4_SCK,SAI1_TX_SYNC,FLEXIO1_D13,GPIO1_IO18,ENET_1588_EVENT3_OUT,KPP_COL5,,,ADC2_IN3,ACMP3_IN2,ALT5 GPIO_AD_B1_03,SEMC_CSX2,FLEXSPI_A_DATA2,LPSPI4_PCS0,SAI1_TX_DATA0,FLEXIO1_D12,GPIO1_IO19,ENET_1588_EVENT3_IN,KPP_ROW5,,,ADC1_IN4,ACMP4_IN2,ALT5 GPIO_AD_B1_04,SEMC_CSX3,FLEXSPI_A_DATA1,LPSPI4_SDO,SAI1_RX_SYNC,FLEXIO1_D11,GPIO1_IO20,LPSPI1_PCS1,KPP_COL6,,,ADC2_IN4,ACMP1_IN3,ALT5 GPIO_AD_B1_05,USDHC1_WP,FLEXSPI_A_SS0_B,LPSPI4_SDI,SAI1_RX_DATA0,FLEXIO1_D10,GPIO1_IO21,LPSPI1_PCS2,KPP_ROW6,,,"ADC1_IN5,ADC2_IN5",ACMP2_IN3,ALT5 -GPIO_AD_B1_06,USDHC1_RESET_B,FLEXPWM1_PWMA0,LPUART2_CTS_B,SAI1_RX_BCLK,FLEXIO1_D09,GPIO1_IO22,LPSPI1_PCS3,KPP_COL7,,,"ADC1_IN6,ADC2_IN6",ACMP3_IN3,ALT5 -GPIO_AD_B1_07,USDHC1_VSELECT,FLEXPWM1_PWMB0,LPUART2_RTS_B,SAI1_TX_DATA1,FLEXIO1_D08,GPIO1_IO23,LPSPI3_PCS3,KPP_ROW7,,,"ADC1_IN7,ADC2_IN7",ACMP4_IN3,ALT5 -GPIO_AD_B1_08,LPI2C2_SCL,FLEXPWM1_PWMA1,LPUART2_TXD,SAI1_TX_DATA2,FLEXIO1_D07,GPIO1_IO24,LPSPI3_PCS2,XBAR_INOUT12,,,"ADC1_IN8,ADC2_IN8",ACMP1_IN5,ALT5 -GPIO_AD_B1_09,LPI2C2_SDA,FLEXPWM1_PWMB1,LPUART2_RXD,SAI1_TX_DATA3,FLEXIO1_D06,GPIO1_IO25,LPSPI3_PCS1,XBAR_INOUT13,,,"ADC1_IN9,ADC2_IN9",ACMP2_IN5,ALT5 -GPIO_AD_B1_10,USB_OTG1_PWR,FLEXPWM1_PWMA2,LPUART4_TXD,USDHC1_CD_B,FLEXIO1_D05,GPIO1_IO26,GPT2_CAPTURE1,,,,"ADC1_IN10,ADC2_IN10",ACMP3_IN5,ALT5 -GPIO_AD_B1_11,USB_OTG1_ID,FLEXPWM1_PWMB2,LPUART4_RXD,USDHC1_WP,FLEXIO1_D04,GPIO1_IO27,GPT2_COMPARE1,,,,"ADC1_IN11,ADC2_IN11",ACMP4_IN5,ALT5 -GPIO_AD_B1_12,USB_OTG1_OC,ACMP1_OUT,LPSPI3_SCK,USDHC2_CD_B,FLEXIO1_D03,GPIO1_IO28,FLEXPWM1_PWMA3,,,,"ADC1_IN12,ADC2_IN12","ACMP1_IN6,ACMP1_OUT",ALT5 -GPIO_AD_B1_13,LPI2C1_HREQ,ACMP2_OUT,LPSPI3_PCS0,USDHC2_WP,FLEXIO1_D02,GPIO1_IO29,FLEXPWM1_PWMB3,,,,"ADC1_IN13,ADC2_IN13","ACMP2_IN6,ACMP2_OUT",ALT5 +GPIO_AD_B1_06,USDHC1_RESET_B,FLEXPWM1_PWM0_A,LPUART2_CTS_B,SAI1_RX_BCLK,FLEXIO1_D09,GPIO1_IO22,LPSPI1_PCS3,KPP_COL7,,,"ADC1_IN6,ADC2_IN6",ACMP3_IN3,ALT5 +GPIO_AD_B1_07,USDHC1_VSELECT,FLEXPWM1_PWM0_B,LPUART2_RTS_B,SAI1_TX_DATA1,FLEXIO1_D08,GPIO1_IO23,LPSPI3_PCS3,KPP_ROW7,,,"ADC1_IN7,ADC2_IN7",ACMP4_IN3,ALT5 +GPIO_AD_B1_08,LPI2C2_SCL,FLEXPWM1_PWM1_A,LPUART2_TXD,SAI1_TX_DATA2,FLEXIO1_D07,GPIO1_IO24,LPSPI3_PCS2,XBAR_INOUT12,,,"ADC1_IN8,ADC2_IN8",ACMP1_IN5,ALT5 +GPIO_AD_B1_09,LPI2C2_SDA,FLEXPWM1_PWM1_B,LPUART2_RXD,SAI1_TX_DATA3,FLEXIO1_D06,GPIO1_IO25,LPSPI3_PCS1,XBAR_INOUT13,,,"ADC1_IN9,ADC2_IN9",ACMP2_IN5,ALT5 +GPIO_AD_B1_10,USB_OTG1_PWR,FLEXPWM1_PWM2_A,LPUART4_TXD,USDHC1_CD_B,FLEXIO1_D05,GPIO1_IO26,GPT2_CAPTURE1,,,,"ADC1_IN10,ADC2_IN10",ACMP3_IN5,ALT5 +GPIO_AD_B1_11,USB_OTG1_ID,FLEXPWM1_PWM2_B,LPUART4_RXD,USDHC1_WP,FLEXIO1_D04,GPIO1_IO27,GPT2_COMPARE1,,,,"ADC1_IN11,ADC2_IN11",ACMP4_IN5,ALT5 +GPIO_AD_B1_12,USB_OTG1_OC,ACMP1_OUT,LPSPI3_SCK,USDHC2_CD_B,FLEXIO1_D03,GPIO1_IO28,FLEXPWM1_PWM3_A,,,,"ADC1_IN12,ADC2_IN12","ACMP1_IN6,ACMP1_OUT",ALT5 +GPIO_AD_B1_13,LPI2C1_HREQ,ACMP2_OUT,LPSPI3_PCS0,USDHC2_WP,FLEXIO1_D02,GPIO1_IO29,FLEXPWM1_PWM3_B,,,,"ADC1_IN13,ADC2_IN13","ACMP2_IN6,ACMP2_OUT",ALT5 GPIO_AD_B1_14,LPI2C1_SCL,ACMP3_OUT,LPSPI3_SDO,ENET_1588_EVENT0_OUT,FLEXIO1_D01,GPIO1_IO30,,,,,"ADC1_IN14,ADC2_IN14","ACMP3_IN6,ACMP3_OUT",ALT5 GPIO_AD_B1_15,LPI2C1_SDA,ACMP4_OUT,LPSPI3_SDI,ENET_1588_EVENT0_IN,FLEXIO1_D00,GPIO1_IO31,,,,,"ADC1_IN15,ADC2_IN15","ACMP4_IN6,ACMP4_OUT",ALT5 GPIO_EMC_00,SEMC_DA00,TMR2_TIMER0,LPUART4_CTS_B,SPDIF_SR_CLK,LPSPI2_SCK,GPIO2_IO00,FLEXCAN1_TX,PIT_TRIGGER2,,,,,ALT5 @@ -41,36 +41,36 @@ GPIO_EMC_06,SEMC_DA06,XBAR_INOUT06,LPUART3_TXD,SAI2_TX_DATA,FLEXIO1_D18,GPIO2_IO GPIO_EMC_07,SEMC_DA07,XBAR_INOUT07,LPUART3_RXD,SAI2_RX_SYNC,FLEXIO1_D19,GPIO2_IO07,USBPHY1_TSTO_RX_SQUELCH,,,,,,ALT5 GPIO_EMC_08,SEMC_DM0,XBAR_INOUT08,FLEXCAN2_TX,SAI2_RX_DATA,FLEXIO1_D20,GPIO2_IO08,USBPHY1_TSTO_RX_DISCON_DET,,,,,,ALT5 GPIO_EMC_09,SEMC_WE,XBAR_INOUT09,FLEXCAN2_RX,SAI2_RX_BCLK,FLEXIO1_D21,GPIO2_IO09,USBPHY1_TSTO_RX_HS_RXD,,,,,,ALT5 -GPIO_EMC_10,SEMC_CAS,XBAR_INOUT10,LPI2C4_SDA,SAI1_TX_SYNC,LPSPI2_SCK,GPIO2_IO10,FLEXPWM2_PWMX0,,,,,,ALT5 -GPIO_EMC_11,SEMC_RAS,XBAR_INOUT11,LPI2C4_SCL,SAI1_TX_BCLK,LPSPI2_PCS0,GPIO2_IO11,FLEXPWM2_PWMX1,,,,,,ALT5 -GPIO_EMC_12,SEMC_CS0,XBAR_INOUT12,LPUART6_TXD,SAI1_TX_DATA0,LPSPI2_SDO,GPIO2_IO12,FLEXPWM2_PWMX2,,,,,,ALT5 -GPIO_EMC_13,SEMC_BA0,XBAR_INOUT13,LPUART6_RXD,SAI1_RX_DATA0,LPSPI2_SDI,GPIO2_IO13,FLEXPWM2_PWMX3,CCM_PMIC_RDY,,,,,ALT5 +GPIO_EMC_10,SEMC_CAS,XBAR_INOUT10,LPI2C4_SDA,SAI1_TX_SYNC,LPSPI2_SCK,GPIO2_IO10,FLEXPWM2_PWM0_X,,,,,,ALT5 +GPIO_EMC_11,SEMC_RAS,XBAR_INOUT11,LPI2C4_SCL,SAI1_TX_BCLK,LPSPI2_PCS0,GPIO2_IO11,FLEXPWM2_PWM1_X,,,,,,ALT5 +GPIO_EMC_12,SEMC_CS0,XBAR_INOUT12,LPUART6_TXD,SAI1_TX_DATA0,LPSPI2_SDO,GPIO2_IO12,FLEXPWM2_PWM2_X,,,,,,ALT5 +GPIO_EMC_13,SEMC_BA0,XBAR_INOUT13,LPUART6_RXD,SAI1_RX_DATA0,LPSPI2_SDI,GPIO2_IO13,FLEXPWM2_PWM3_X,CCM_PMIC_RDY,,,,,ALT5 GPIO_EMC_14,SEMC_BA1,XBAR_INOUT14,LPUART6_CTS_B,SAI1_RX_BCLK,LPSPI2_PCS1,GPIO2_IO14,FLEXCAN1_TX,,,,,,ALT5 GPIO_EMC_15,SEMC_ADDR10,XBAR_INOUT15,LPUART6_RTS_B,SAI1_RX_SYNC,WDOG1_B,GPIO2_IO15,FLEXCAN1_RX,,,,,,ALT5 GPIO_EMC_16,SEMC_ADDR00,,MQS_RIGHT,SAI2_MCLK,,GPIO2_IO16,SRC_BOOT_MODE0,,,,,,ALT5 GPIO_EMC_17,SEMC_ADDR01,,MQS_LEFT,SAI3_MCLK,,GPIO2_IO17,SRC_BOOT_MODE1,,,,,,ALT5 GPIO_EMC_18,SEMC_ADDR02,XBAR_INOUT16,LPI2C2_SDA,SAI1_RX_SYNC,FLEXIO1_D22,GPIO2_IO18,SRC_BT_CFG0,,,,,,ALT5 GPIO_EMC_19,SEMC_ADDR03,XBAR_INOUT17,LPI2C2_SCL,SAI1_RX_BCLK,FLEXIO1_D23,GPIO2_IO19,SRC_BT_CFG1,,,,,,ALT5 -GPIO_EMC_20,SEMC_ADDR04,FLEXPWM1_PWMA3,LPUART2_CTS_B,SAI1_MCLK,FLEXIO1_D24,GPIO2_IO20,SRC_BT_CFG2,,,,,,ALT5 -GPIO_EMC_21,SEMC_ADDR05,FLEXPWM1_PWMB3,LPUART2_RTS_B,SAI1_RX_DATA0,FLEXIO1_D25,GPIO2_IO21,SRC_BT_CFG3,,,,,,ALT5 -GPIO_EMC_22,SEMC_ADDR06,FLEXPWM1_PWMA2,LPUART2_TXD,SAI1_TX_DATA3,FLEXIO1_D26,GPIO2_IO22,SRC_BT_CFG4,,,,,,ALT5 -GPIO_EMC_23,SEMC_ADDR07,FLEXPWM1_PWMB2,LPUART2_RXD,SAI1_TX_DATA2,FLEXIO1_D27,GPIO2_IO23,SRC_BT_CFG5,,,,,,ALT5 -GPIO_EMC_24,SEMC_ADDR08,FLEXPWM1_PWMA1,LPUART8_CTS_B,SAI1_TX_DATA1,FLEXIO1_D28,GPIO2_IO24,SRC_BT_CFG6,,,,,,ALT5 -GPIO_EMC_25,SEMC_ADDR09,FLEXPWM1_PWMB1,LPUART8_RTS_B,SAI1_TX_DATA0,FLEXIO1_D29,GPIO2_IO25,SRC_BT_CFG7,,,,,,ALT5 -GPIO_EMC_26,SEMC_ADDR11,FLEXPWM1_PWMA0,LPUART8_TXD,SAI1_TX_BCLK,FLEXIO1_D30,GPIO2_IO26,SRC_BT_CFG8,,,,,,ALT5 -GPIO_EMC_27,SEMC_ADDR12,FLEXPWM1_PWMB0,LPUART8_RXD,SAI1_TX_SYNC,FLEXIO1_D31,GPIO2_IO27,SRC_BT_CFG9,,,,,,ALT5 -GPIO_EMC_28,SEMC_DQS,FLEXPWM2_PWMA3,XBAR_INOUT18,SAI3_MCLK,EWM_OUT_B,GPIO2_IO28,GPT2_CAPTURE2,FLEXPWM1_PWMX0,,,,,ALT5 -GPIO_EMC_29,SEMC_CKE,FLEXPWM2_PWMB3,XBAR_INOUT19,SAI3_RX_BCLK,WDOG2_RST_B_DEB,GPIO2_IO29,GPT2_COMPARE2,FLEXPWM1_PWMX1,,,,,ALT5 -GPIO_EMC_30,SEMC_CLK,FLEXPWM2_PWMA2,LPUART4_CTS_B,SAI3_RX_SYNC,WDOG1_RST_B_DEB,GPIO2_IO30,GPT2_COMPARE3,FLEXPWM1_PWMX2,,,,,ALT5 -GPIO_EMC_31,SEMC_DM1,FLEXPWM2_PWMB2,LPUART4_RTS_B,SAI3_RX_DATA,WDOG2_B,GPIO2_IO31,GPT2_CLK,FLEXPWM1_PWMX3,,,,,ALT5 +GPIO_EMC_20,SEMC_ADDR04,FLEXPWM1_PWM3_A,LPUART2_CTS_B,SAI1_MCLK,FLEXIO1_D24,GPIO2_IO20,SRC_BT_CFG2,,,,,,ALT5 +GPIO_EMC_21,SEMC_ADDR05,FLEXPWM1_PWM3_B,LPUART2_RTS_B,SAI1_RX_DATA0,FLEXIO1_D25,GPIO2_IO21,SRC_BT_CFG3,,,,,,ALT5 +GPIO_EMC_22,SEMC_ADDR06,FLEXPWM1_PWM2_A,LPUART2_TXD,SAI1_TX_DATA3,FLEXIO1_D26,GPIO2_IO22,SRC_BT_CFG4,,,,,,ALT5 +GPIO_EMC_23,SEMC_ADDR07,FLEXPWM1_PWM2_B,LPUART2_RXD,SAI1_TX_DATA2,FLEXIO1_D27,GPIO2_IO23,SRC_BT_CFG5,,,,,,ALT5 +GPIO_EMC_24,SEMC_ADDR08,FLEXPWM1_PWM1_A,LPUART8_CTS_B,SAI1_TX_DATA1,FLEXIO1_D28,GPIO2_IO24,SRC_BT_CFG6,,,,,,ALT5 +GPIO_EMC_25,SEMC_ADDR09,FLEXPWM1_PWM1_B,LPUART8_RTS_B,SAI1_TX_DATA0,FLEXIO1_D29,GPIO2_IO25,SRC_BT_CFG7,,,,,,ALT5 +GPIO_EMC_26,SEMC_ADDR11,FLEXPWM1_PWM0_A,LPUART8_TXD,SAI1_TX_BCLK,FLEXIO1_D30,GPIO2_IO26,SRC_BT_CFG8,,,,,,ALT5 +GPIO_EMC_27,SEMC_ADDR12,FLEXPWM1_PWM0_B,LPUART8_RXD,SAI1_TX_SYNC,FLEXIO1_D31,GPIO2_IO27,SRC_BT_CFG9,,,,,,ALT5 +GPIO_EMC_28,SEMC_DQS,FLEXPWM2_PWM3_A,XBAR_INOUT18,SAI3_MCLK,EWM_OUT_B,GPIO2_IO28,GPT2_CAPTURE2,FLEXPWM1_PWM0_X,,,,,ALT5 +GPIO_EMC_29,SEMC_CKE,FLEXPWM2_PWM3_B,XBAR_INOUT19,SAI3_RX_BCLK,WDOG2_RST_B_DEB,GPIO2_IO29,GPT2_COMPARE2,FLEXPWM1_PWM1_X,,,,,ALT5 +GPIO_EMC_30,SEMC_CLK,FLEXPWM2_PWM2_A,LPUART4_CTS_B,SAI3_RX_SYNC,WDOG1_RST_B_DEB,GPIO2_IO30,GPT2_COMPARE3,FLEXPWM1_PWM2_X,,,,,ALT5 +GPIO_EMC_31,SEMC_DM1,FLEXPWM2_PWM2_B,LPUART4_RTS_B,SAI3_RX_DATA,WDOG2_B,GPIO2_IO31,GPT2_CLK,FLEXPWM1_PWM3_X,,,,,ALT5 GPIO_EMC_32,SEMC_DA08,TMR1_TIMER0,LPUART4_TXD,SAI3_TX_DATA,LPSPI4_SCK,GPIO3_IO00,USBPHY1_TSTO_RX_FS_RXD,REF_24M_OUT,,,,,ALT5 GPIO_EMC_33,SEMC_DA09,TMR1_TIMER1,LPUART4_RXD,SAI3_TX_BCLK,LPSPI4_PCS0,GPIO3_IO01,USBPHY1_TSTI_TX_DP,SRC_TESTER_ACK,,,,,ALT5 GPIO_EMC_34,SEMC_DA10,TMR1_TIMER2,LPUART7_TXD,SAI3_TX_SYNC,LPSPI4_SDO,GPIO3_IO02,ENET_CRS,,,,,,ALT5 GPIO_EMC_35,SEMC_DA11,TMR1_TIMER3,LPUART7_RXD,USDHC2_WP,LPSPI4_SDI,GPIO3_IO03,ENET_COL,,,,,,ALT5 -GPIO_EMC_36,SEMC_DA12,FLEXPWM2_PWMA1,LPUART5_CTS_B,CCM_PMIC_RDY,LPSPI4_PCS1,GPIO3_IO04,ENET_RX_CLK,USDHC1_WP,,,,,ALT5 -GPIO_EMC_37,SEMC_DA13,FLEXPWM2_PWMB1,LPUART5_RTS_B,MQS_RIGHT,LPSPI4_PCS2,GPIO3_IO05,ENET_RX_DATA3,USDHC1_VSELECT,,,,,ALT5 -GPIO_EMC_38,SEMC_DA14,FLEXPWM2_PWMA0,LPUART5_TXD,MQS_LEFT,LPSPI4_PCS3,GPIO3_IO06,ENET_RX_DATA2,USDHC1_CD_B,,,,,ALT5 -GPIO_EMC_39,SEMC_DA15,FLEXPWM2_PWMB0,LPUART5_RXD,USB_OTG1_OC,WDOG1_B,GPIO3_IO07,ENET_TX_ER,GPT1_CLK,,,,,ALT5 +GPIO_EMC_36,SEMC_DA12,FLEXPWM2_PWM1_A,LPUART5_CTS_B,CCM_PMIC_RDY,LPSPI4_PCS1,GPIO3_IO04,ENET_RX_CLK,USDHC1_WP,,,,,ALT5 +GPIO_EMC_37,SEMC_DA13,FLEXPWM2_PWM1_B,LPUART5_RTS_B,MQS_RIGHT,LPSPI4_PCS2,GPIO3_IO05,ENET_RX_DATA3,USDHC1_VSELECT,,,,,ALT5 +GPIO_EMC_38,SEMC_DA14,FLEXPWM2_PWM0_A,LPUART5_TXD,MQS_LEFT,LPSPI4_PCS3,GPIO3_IO06,ENET_RX_DATA2,USDHC1_CD_B,,,,,ALT5 +GPIO_EMC_39,SEMC_DA15,FLEXPWM2_PWM0_B,LPUART5_RXD,USB_OTG1_OC,WDOG1_B,GPIO3_IO07,ENET_TX_ER,GPT1_CLK,,,,,ALT5 GPIO_EMC_40,SEMC_CSX0,XBAR_INOUT18,SPDIF_OUT,USB_OTG1_ID,ENET_MDIO,GPIO3_IO08,ENET_TX_DATA3,GPT1_COMPARE3,,,,,ALT5 GPIO_EMC_41,SEMC_RDY,XBAR_INOUT19,SPDIF_IN,USB_OTG1_PWR,ENET_MDC,GPIO3_IO09,ENET_TX_DATA2,GPT1_COMPARE2,,,,,ALT5 GPIO_SD_B0_00,USDHC1_DATA2,TMR1_TIMER0,SAI1_MCLK,SAI2_MCLK,LPI2C3_SCL,GPIO3_IO13,FLEXSPI_A_SS1_B,XBAR_INOUT14,,,,,ALT5 diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK.ld b/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK.ld deleted file mode 100644 index fd1bf32ed..000000000 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/MIMXRT1050_EVK.ld +++ /dev/null @@ -1 +0,0 @@ -flash_size = 8M; \ No newline at end of file diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/board.json b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json new file mode 100644 index 000000000..d99ad9fcf --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/board.json @@ -0,0 +1,26 @@ +{ + "deploy": [ + "../deploy_mimxrt.md" + ], + "docs": "", + "features": [ + "Ethernet", + "SDRAM", + "MicroSD", + "MicroUSB", + "Microphone", + "AudioCodec", + "SPDIF", + "CAN", + "OpenSDA", + "JLink" + ], + "images": [ + "IMX_RT1050-EVKB_TOP-LR.jpg" + ], + "mcu": "mimxrt", + "product": "MIMXRT1050_EVK", + "thumbnail": "", + "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1050-evaluation-kit:MIMXRT1050-EVK", + "vendor": "NXP" +} diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1050_EVK/clock_config.h new file mode 100644 index 000000000..f213ac7e2 --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/clock_config.h @@ -0,0 +1,119 @@ +/* + * Copyright 2017-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */ +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockRUN configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */ + +/* Clock outputs (values are in Hz): */ +#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL +#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL +#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL +#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL +#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL +#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL +#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 160000000UL +#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL +#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL +#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL +#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL +#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL +#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL +#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL +#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL +#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL +#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL +#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL +#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL + +/*! @brief Arm PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN; +/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN; +/*! @brief Sys PLL for BOARD_BootClockRUN configuration. + */ +extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN; + +/******************************************************************************* + * API for BOARD_BootClockRUN configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockRUN(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h deleted file mode 100644 index e038967e1..000000000 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/evkmimxrt1050_flexspi_nor_config.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ -#define __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ - -#include -#include -#include "fsl_common.h" - -/*! @name Driver version */ -/*@{*/ -/*! @brief XIP_BOARD driver version 2.0.0. */ -#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) -/*@}*/ - -/* FLEXSPI memory config block related defintions */ -#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian -#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 -#define FLEXSPI_CFG_BLK_SIZE (512) - -/* FLEXSPI Feature related definitions */ -#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 - -/* Lookup table related defintions */ -#define CMD_INDEX_READ 0 -#define CMD_INDEX_READSTATUS 1 -#define CMD_INDEX_WRITEENABLE 2 -#define CMD_INDEX_WRITE 4 - -#define CMD_LUT_SEQ_IDX_READ 0 -#define CMD_LUT_SEQ_IDX_READSTATUS 1 -#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define CMD_LUT_SEQ_IDX_WRITE 9 - -#define CMD_SDR 0x01 -#define CMD_DDR 0x21 -#define RADDR_SDR 0x02 -#define RADDR_DDR 0x22 -#define CADDR_SDR 0x03 -#define CADDR_DDR 0x23 -#define MODE1_SDR 0x04 -#define MODE1_DDR 0x24 -#define MODE2_SDR 0x05 -#define MODE2_DDR 0x25 -#define MODE4_SDR 0x06 -#define MODE4_DDR 0x26 -#define MODE8_SDR 0x07 -#define MODE8_DDR 0x27 -#define WRITE_SDR 0x08 -#define WRITE_DDR 0x28 -#define READ_SDR 0x09 -#define READ_DDR 0x29 -#define LEARN_SDR 0x0A -#define LEARN_DDR 0x2A -#define DATSZ_SDR 0x0B -#define DATSZ_DDR 0x2B -#define DUMMY_SDR 0x0C -#define DUMMY_DDR 0x2C -#define DUMMY_RWDS_SDR 0x0D -#define DUMMY_RWDS_DDR 0x2D -#define JMP_ON_CS 0x1F -#define STOP 0 - -#define FLEXSPI_1PAD 0 -#define FLEXSPI_2PAD 1 -#define FLEXSPI_4PAD 2 -#define FLEXSPI_8PAD 3 - -#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ - (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ - FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) - -//!@brief Definitions for FlexSPI Serial Clock Frequency -typedef enum _FlexSpiSerialClockFreq -{ - kFlexSpiSerialClk_30MHz = 1, - kFlexSpiSerialClk_50MHz = 2, - kFlexSpiSerialClk_60MHz = 3, - kFlexSpiSerialClk_75MHz = 4, - kFlexSpiSerialClk_80MHz = 5, - kFlexSpiSerialClk_100MHz = 6, - kFlexSpiSerialClk_133MHz = 7, - kFlexSpiSerialClk_166MHz = 8, -} flexspi_serial_clk_freq_t; - -//!@brief FlexSPI clock configuration type -enum -{ - kFlexSpiClk_SDR, //!< Clock configure for SDR mode - kFlexSpiClk_DDR, //!< Clock configurat for DDR mode -}; - -//!@brief FlexSPI Read Sample Clock Source definition -typedef enum _FlashReadSampleClkSource -{ - kFlexSPIReadSampleClk_LoopbackInternally = 0, - kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, - kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, - kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, -} flexspi_read_sample_clk_t; - -//!@brief Misc feature bit definitions -enum -{ - kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable - kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable - kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable - kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable - kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable - kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable - kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. -}; - -//!@brief Flash Type Definition -enum -{ - kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR - kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND - kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH - kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND - kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs -}; - -//!@brief Flash Pad Definitions -enum -{ - kSerialFlash_1Pad = 1, - kSerialFlash_2Pads = 2, - kSerialFlash_4Pads = 4, - kSerialFlash_8Pads = 8, -}; - -//!@brief FlexSPI LUT Sequence structure -typedef struct _lut_sequence -{ - uint8_t seqNum; //!< Sequence Number, valid number: 1-16 - uint8_t seqId; //!< Sequence Index, valid number: 0-15 - uint16_t reserved; -} flexspi_lut_seq_t; - -//!@brief Flash Configuration Command Type -enum -{ - kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc - kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command - kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode - kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode - kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode - kDeviceConfigCmdType_Reset, //!< Reset device command -}; - -//!@brief FlexSPI Memory Configuration Block -typedef struct _FlexSPIConfig -{ - uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL - uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix - uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use - uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 - uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 - uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 - uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For - //! Serial NAND, need to refer to datasheet - uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable - uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, - //! Generic configuration, etc. - uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for - //! DPI/QPI/OPI switch or reset command - flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt - //! sequence number, [31:16] Reserved - uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration - uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable - uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe - flexspi_lut_seq_t - configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq - uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use - uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands - uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use - uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more - //! details - uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details - uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal - uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot - //! Chapter for more details - uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot - //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH - uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use - uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 - uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 - uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 - uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 - uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value - uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value - uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value - uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value - uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command - uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands - uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns - uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 - uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - - //! busy flag is 0 when flash device is busy - uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences - flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences - uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use -} flexspi_mem_config_t; - -/* */ -#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 -#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 -#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 -#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 -#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 -#define NOR_CMD_LUT_SEQ_IDX_READID 8 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 -#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 -#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 -#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 - -/* - * Serial NOR configuration block - */ -typedef struct _flexspi_nor_config -{ - flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI - uint32_t pageSize; //!< Page size of Serial NOR - uint32_t sectorSize; //!< Sector size of Serial NOR - uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command - uint8_t isUniformBlockSize; //!< Sector/Block size is the same - uint8_t reserved0[2]; //!< Reserved for future use - uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 - uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command - uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false - uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution - uint32_t blockSize; //!< Block size - uint32_t reserve2[11]; //!< Reserved for future use -} flexspi_nor_config_t; - -#define FLASH_BUSY_STATUS_POL 0 -#define FLASH_BUSY_STATUS_OFFSET 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif -#endif /* __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c deleted file mode 100644 index 2a9303fc9..000000000 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/flash_config.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "evkmimxrt1050_flexspi_nor_config.h" - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.xip_board" -#endif - -/******************************************************************************* - * Code - ******************************************************************************/ -#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) -#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) -__attribute__((section(".boot_hdr.conf"))) -#elif defined(__ICCARM__) -#pragma location = ".boot_hdr.conf" -#endif - -const flexspi_nor_config_t qspiflash_config = { - .memConfig = - { - .tag = FLEXSPI_CFG_BLK_TAG, - .version = FLEXSPI_CFG_BLK_VERSION, - .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad, - .csHoldTime = 3u, - .csSetupTime = 3u, - .columnAddressWidth = 3u, - // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock - .controllerMiscOption = - (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) | - (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable), - .sflashPadType = kSerialFlash_8Pads, - .serialClkFreq = kFlexSpiSerialClk_133MHz, - .sflashA1Size = 64u * 1024u * 1024u, - .dataValidTime = {16u, 16u}, - .lookupTable = - { - // 0 Read LUTs 0 -> 0 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 1 Read status register -> 1 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 2 Fast read quad mode - SDR - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 3 Write Enable -> 3 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 4 Read extend parameters - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 5 Erase Sector -> 5 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 6 Write Status Reg - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 7 Page Program - quad mode (-> 9) - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 8 Read ID - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 9 Page Program - single mode -> 9 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 10 Enter QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 11 Erase Chip - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 12 Exit QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - }, - }, - .pageSize = 512u, - .sectorSize = 256u * 1024u, - .blockSize = 256u * 1024u, - .isUniformBlockSize = true, -}; - -#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h index af0975bc1..aa9ab8d95 100644 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h @@ -1,28 +1,25 @@ -#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVK" +#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVKB-A1" #define MICROPY_HW_MCU_NAME "MIMXRT1052DVL6B" -#define BOARD_FLASH_SIZE (64 * 1024 * 1024) - -// MIMXRT1050_EVK has 1 user LED +// MIMXRT1050_EVKB has 1 user LED #define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09) #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) -#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1050_flexspi_nor_config.h" -#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h" #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) // Define mapping logical UART # to hardware UART # -// LPUART3 on D0/D1 -> 1 -// LPUART2 on D7/D6 -> 2 -// LPUART6 on D8/D9 -> 3 -// LPUART8 on A1/A0 -> 4 +// LPUART1 on USB_DBG -> 0 +// LPUART3 on D0/D1 -> 1 +// LPUART2 on D7/D6 -> 2 +// LPUART6 on D8/D9 -> 3 +// LPUART8 on A1/A0 -> 4 #define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) -#define MICROPY_HW_UART_INDEX { 0, 3, 2, 6, 8 } +#define MICROPY_HW_UART_INDEX { 1, 3, 2, 6, 8 } #define IOMUX_TABLE_UART \ - { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \ { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \ { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \ { 0 }, { 0 }, \ @@ -38,10 +35,10 @@ { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI }, #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \ - kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } + kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ - kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } // Define the mapping hardware I2C # to logical I2C # // SDA/SCL HW-I2C Logical I2C @@ -54,3 +51,82 @@ { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, + +#define USDHC_DUMMY_PIN NULL, 0 + +#define MICROPY_USDHC1 \ + { \ + .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \ + .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \ + .cd_b = { GPIO_B1_12_USDHC1_CD_B }, \ + .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \ + .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \ + .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \ + .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \ + } + +// --- SEMC --- // +#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00 +#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01 +#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02 +#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03 +#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04 +#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05 +#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06 +#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07 +#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_30_SEMC_DATA08 +#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_31_SEMC_DATA09 +#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_32_SEMC_DATA10 +#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_33_SEMC_DATA11 +#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_34_SEMC_DATA12 +#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_35_SEMC_DATA13 +#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_36_SEMC_DATA14 +#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_37_SEMC_DATA15 + +#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_09_SEMC_ADDR00 +#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_10_SEMC_ADDR01 +#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_11_SEMC_ADDR02 +#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_12_SEMC_ADDR03 +#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_13_SEMC_ADDR04 +#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_14_SEMC_ADDR05 +#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_15_SEMC_ADDR06 +#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_16_SEMC_ADDR07 +#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_17_SEMC_ADDR08 +#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_18_SEMC_ADDR09 +#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_23_SEMC_ADDR10 +#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_19_SEMC_ADDR11 +#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_20_SEMC_ADDR12 + +#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_21_SEMC_BA0 +#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_22_SEMC_BA1 +#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_24_SEMC_CAS +#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_27_SEMC_CKE +#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_26_SEMC_CLK +#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00 +#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_38_SEMC_DM01 +#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_39_SEMC_DQS +#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_25_SEMC_RAS +#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE + +#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0 + +// Network definitions +// Transceiver Phy Address & Type +#define ENET_PHY_ADDRESS (2) +#define ENET_PHY_OPS phyksz8081_ops + +// Etherner PIN definitions +#define ENET_RESET_PIN pin_GPIO_AD_B0_09 +#define ENET_INT_PIN pin_GPIO_AD_B0_10 + +#define IOMUX_TABLE_ENET \ + { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \ + { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u }, diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk index 61826b6f6..65e3d3096 100644 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk @@ -2,11 +2,13 @@ MCU_SERIES = MIMXRT1052 MCU_VARIANT = MIMXRT1052DVL6B MICROPY_FLOAT_IMPL = double +MICROPY_PY_MACHINE_SDCARD = 1 +MICROPY_HW_FLASH_TYPE ?= hyperflash +MICROPY_HW_FLASH_SIZE ?= 0x4000000 # 64MB -SRC_C += \ - hal/flexspi_nor_flash.c \ +MICROPY_HW_SDRAM_AVAIL = 1 +MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB -JLINK_PATH ?= /media/RT1050-EVK/ - -deploy: $(BUILD)/firmware.bin - cp $< $(JLINK_PATH) +MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/pins.csv b/ports/mimxrt/boards/MIMXRT1050_EVK/pins.csv index 366a141ff..463079b12 100644 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/pins.csv +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/pins.csv @@ -12,8 +12,8 @@ D10,GPIO_SD_B0_01 D11,GPIO_SD_B0_02 D12,GPIO_SD_B0_03 D13,GPIO_SD_B0_00 -D14,GPIO_AD_B1_01 -D15,GPIO_AD_B1_00 +D14,GPIO_AD_B0_01 +D15,GPIO_AD_B0_00 A0,GPIO_AD_B1_10 A1,GPIO_AD_B1_11 A2,GPIO_AD_B1_04 diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld b/ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld deleted file mode 100644 index f616178a9..000000000 --- a/ports/mimxrt/boards/MIMXRT1050_EVKB/MIMXRT1050_EVKB.ld +++ /dev/null @@ -1 +0,0 @@ -flash_size = 64M; \ No newline at end of file diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h deleted file mode 100644 index 02ac394e9..000000000 --- a/ports/mimxrt/boards/MIMXRT1050_EVKB/evkbmimxrt1050_flexspi_nor_config.h +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ -#define __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ - -#include -#include -#include "fsl_flexspi.h" - -/*! @name Driver version */ -/*@{*/ -/*! @brief XIP_BOARD driver version 2.0.0. */ -#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) -/*@}*/ - -/* FLEXSPI memory config block related defintions */ -#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian -#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 -#define FLEXSPI_CFG_BLK_SIZE (512) - -/* FLEXSPI Feature related definitions */ -#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 - -/* Lookup table related defintions */ -#define CMD_INDEX_READ 0 -#define CMD_INDEX_READSTATUS 1 -#define CMD_INDEX_WRITEENABLE 2 -#define CMD_INDEX_WRITE 4 - -#define CMD_LUT_SEQ_IDX_READ 0 -#define CMD_LUT_SEQ_IDX_READSTATUS 1 -#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define CMD_LUT_SEQ_IDX_WRITE 9 - -#define CMD_SDR 0x01 -#define CMD_DDR 0x21 -#define RADDR_SDR 0x02 -#define RADDR_DDR 0x22 -#define CADDR_SDR 0x03 -#define CADDR_DDR 0x23 -#define MODE1_SDR 0x04 -#define MODE1_DDR 0x24 -#define MODE2_SDR 0x05 -#define MODE2_DDR 0x25 -#define MODE4_SDR 0x06 -#define MODE4_DDR 0x26 -#define MODE8_SDR 0x07 -#define MODE8_DDR 0x27 -#define WRITE_SDR 0x08 -#define WRITE_DDR 0x28 -#define READ_SDR 0x09 -#define READ_DDR 0x29 -#define LEARN_SDR 0x0A -#define LEARN_DDR 0x2A -#define DATSZ_SDR 0x0B -#define DATSZ_DDR 0x2B -#define DUMMY_SDR 0x0C -#define DUMMY_DDR 0x2C -#define DUMMY_RWDS_SDR 0x0D -#define DUMMY_RWDS_DDR 0x2D -#define JMP_ON_CS 0x1F -#define STOP 0 - -#define FLEXSPI_1PAD 0 -#define FLEXSPI_2PAD 1 -#define FLEXSPI_4PAD 2 -#define FLEXSPI_8PAD 3 - -#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ - (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ - FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) - -//!@brief Definitions for FlexSPI Serial Clock Frequency -typedef enum _FlexSpiSerialClockFreq -{ - kFlexSpiSerialClk_30MHz = 1, - kFlexSpiSerialClk_50MHz = 2, - kFlexSpiSerialClk_60MHz = 3, - kFlexSpiSerialClk_75MHz = 4, - kFlexSpiSerialClk_80MHz = 5, - kFlexSpiSerialClk_100MHz = 6, - kFlexSpiSerialClk_133MHz = 7, - kFlexSpiSerialClk_166MHz = 8, -} flexspi_serial_clk_freq_t; - -//!@brief FlexSPI clock configuration type -enum -{ - kFlexSpiClk_SDR, //!< Clock configure for SDR mode - kFlexSpiClk_DDR, //!< Clock configurat for DDR mode -}; - -//!@brief FlexSPI Read Sample Clock Source definition -typedef enum _FlashReadSampleClkSource -{ - kFlexSPIReadSampleClk_LoopbackInternally = 0, - kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, - kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, - kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, -} flexspi_read_sample_clk_t; - -//!@brief Misc feature bit definitions -enum -{ - kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable - kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable - kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable - kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable - kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable - kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable - kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. -}; - -//!@brief Flash Type Definition -enum -{ - kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR - kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND - kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH - kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND - kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs -}; - -//!@brief Flash Pad Definitions -enum -{ - kSerialFlash_1Pad = 1, - kSerialFlash_2Pads = 2, - kSerialFlash_4Pads = 4, - kSerialFlash_8Pads = 8, -}; - -//!@brief FlexSPI LUT Sequence structure -typedef struct _lut_sequence -{ - uint8_t seqNum; //!< Sequence Number, valid number: 1-16 - uint8_t seqId; //!< Sequence Index, valid number: 0-15 - uint16_t reserved; -} flexspi_lut_seq_t; - -//!@brief Flash Configuration Command Type -enum -{ - kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc - kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command - kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode - kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode - kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode - kDeviceConfigCmdType_Reset, //!< Reset device command -}; - -//!@brief FlexSPI Memory Configuration Block -typedef struct _FlexSPIConfig -{ - uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL - uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix - uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use - uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 - uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 - uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 - uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For - //! Serial NAND, need to refer to datasheet - uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable - uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, - //! Generic configuration, etc. - uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for - //! DPI/QPI/OPI switch or reset command - flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt - //! sequence number, [31:16] Reserved - uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration - uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable - uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe - flexspi_lut_seq_t - configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq - uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use - uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands - uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use - uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more - //! details - uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details - uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal - uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot - //! Chapter for more details - uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot - //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH - uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use - uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 - uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 - uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 - uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 - uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value - uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value - uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value - uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value - uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command - uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands - uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns - uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 - uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - - //! busy flag is 0 when flash device is busy - uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences - flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences - uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use -} flexspi_mem_config_t; - -/* */ -#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 -#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 -#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 -#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 -#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 -#define NOR_CMD_LUT_SEQ_IDX_READID 8 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 -#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 -#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 -#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 - -#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS 2 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP 12 - -/* - * Serial NOR configuration block - */ -typedef struct _flexspi_nor_config -{ - flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI - uint32_t pageSize; //!< Page size of Serial NOR - uint32_t sectorSize; //!< Sector size of Serial NOR - uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command - uint8_t isUniformBlockSize; //!< Sector/Block size is the same - uint8_t reserved0[2]; //!< Reserved for future use - uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 - uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command - uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false - uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution - uint32_t blockSize; //!< Block size - uint32_t reserve2[11]; //!< Reserved for future use -} flexspi_nor_config_t; - -#define FLASH_BUSY_STATUS_POL 0 -#define FLASH_BUSY_STATUS_OFFSET 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif -#endif /* __EVKMIMXRT1050_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c b/ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c deleted file mode 100644 index e8190bcb6..000000000 --- a/ports/mimxrt/boards/MIMXRT1050_EVKB/flash_config.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "evkbmimxrt1050_flexspi_nor_config.h" - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.xip_board" -#endif - -/******************************************************************************* - * Code - ******************************************************************************/ -#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) -#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) -__attribute__((section(".boot_hdr.conf"))) -#elif defined(__ICCARM__) -#pragma location = ".boot_hdr.conf" -#endif - -const flexspi_nor_config_t qspiflash_config = { - .memConfig = - { - .tag = FLEXSPI_CFG_BLK_TAG, - .version = FLEXSPI_CFG_BLK_VERSION, - .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad, - .csHoldTime = 3u, - .csSetupTime = 3u, - .columnAddressWidth = 3u, - // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock - .controllerMiscOption = - (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) | - (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable), - .sflashPadType = kSerialFlash_8Pads, - .serialClkFreq = kFlexSpiSerialClk_133MHz, - .sflashA1Size = 64u * 1024u * 1024u, - .dataValidTime = {16u, 16u}, - .lookupTable = - { - /* 0 Read Data */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04), - - /* 1 Write Data */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02), - - /* 2 Read Status */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70 - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), - - /* 4 Write Enable */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - - /* 6 Erase Sector */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80 - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - // +2 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - // +3 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), - - /* 10 program page with word program command sequence */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0 - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80), - - /* 12 Erase chip */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - // +2 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - // +3 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10), - }, - }, - .pageSize = 512u, - .sectorSize = 256u * 1024u, - .blockSize = 256u * 1024u, - .isUniformBlockSize = true, -}; - -#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h deleted file mode 100644 index 518240b03..000000000 --- a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.h +++ /dev/null @@ -1,69 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVKB" -#define MICROPY_HW_MCU_NAME "MIMXRT1052DVL6B" - -#define BOARD_FLASH_SIZE (64 * 1024 * 1024) - -// MIMXRT1050_EVKB has 1 user LED -#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09) -#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) -#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) -#define BOARD_FLASH_CONFIG_HEADER_H "evkbmimxrt1050_flexspi_nor_config.h" -#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_hyper_flash.h" - -#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) - -// Define mapping logical UART # to hardware UART # -// LPUART3 on D0/D1 -> 1 -// LPUART2 on D7/D6 -> 2 -// LPUART6 on D8/D9 -> 3 -// LPUART8 on A1/A0 -> 4 - -#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) -#define MICROPY_HW_UART_INDEX { 0, 3, 2, 6, 8 } - -#define IOMUX_TABLE_UART \ - { 0 }, { 0 }, \ - { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \ - { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \ - { 0 }, { 0 }, \ - { 0 }, { 0 }, \ - { IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \ - { 0 }, { 0 }, \ - { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX }, - -#define MICROPY_HW_SPI_INDEX { 1 } - -#define IOMUX_TABLE_SPI \ - { IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \ - { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI }, - -#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \ - kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } - -#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ - kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } - -// Define the mapping hardware I2C # to logical I2C # -// SDA/SCL HW-I2C Logical I2C -// D14/D15 LPI2C1 -> 0 -// D1/D0 LPI2C3 -> 1 - -#define MICROPY_HW_I2C_INDEX { 1, 3 } - -#define IOMUX_TABLE_I2C \ - { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ - { 0 }, { 0 }, \ - { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, - -#define USDHC_DUMMY_PIN NULL , 0 - -#define MICROPY_USDHC1 \ - { \ - .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \ - .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \ - .cd_b = { GPIO_B1_12_USDHC1_CD_B },\ - .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 },\ - .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 },\ - .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 },\ - .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 },\ - } diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk deleted file mode 100644 index c9e32612c..000000000 --- a/ports/mimxrt/boards/MIMXRT1050_EVKB/mpconfigboard.mk +++ /dev/null @@ -1,12 +0,0 @@ -MCU_SERIES = MIMXRT1052 -MCU_VARIANT = MIMXRT1052DVL6B - -MICROPY_FLOAT_IMPL = double - -SRC_C += \ - hal/flexspi_hyper_flash.c \ - -JLINK_PATH ?= /media/RT1050-EVKB/ - -deploy: $(BUILD)/firmware.bin - cp $< $(JLINK_PATH) diff --git a/ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv b/ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv deleted file mode 100644 index 366a141ff..000000000 --- a/ports/mimxrt/boards/MIMXRT1050_EVKB/pins.csv +++ /dev/null @@ -1,31 +0,0 @@ -D0,GPIO_AD_B1_07 -D1,GPIO_AD_B1_06 -D2,GPIO_AD_B0_11 -D3,GPIO_AD_B1_08 -D4,GPIO_AD_B0_09 -D5,GPIO_AD_B0_10 -D6,GPIO_AD_B1_02 -D7,GPIO_AD_B1_03 -D8,GPIO_AD_B0_03 -D9,GPIO_AD_B0_02 -D10,GPIO_SD_B0_01 -D11,GPIO_SD_B0_02 -D12,GPIO_SD_B0_03 -D13,GPIO_SD_B0_00 -D14,GPIO_AD_B1_01 -D15,GPIO_AD_B1_00 -A0,GPIO_AD_B1_10 -A1,GPIO_AD_B1_11 -A2,GPIO_AD_B1_04 -A3,GPIO_AD_B1_05 -A4,GPIO_AD_B1_01 -A5,GPIO_AD_B1_00 -RX,GPIO_AD_B1_07 -TX,GPIO_AD_B1_06 -SCL,GPIO_AD_B1_00 -SDA,GPIO_AD_B1_01 -SCK,GPIO_SD_B0_00 -SDI,GPIO_SD_B0_03 -SDO,GPIO_SD_B0_02 -CS,GPIO_SD_B0_01 -LED_GREEN,GPIO_AD_B0_09 diff --git a/ports/mimxrt/boards/MIMXRT1052.ld b/ports/mimxrt/boards/MIMXRT1052.ld index 751929794..f7c60d24f 100644 --- a/ports/mimxrt/boards/MIMXRT1052.ld +++ b/ports/mimxrt/boards/MIMXRT1052.ld @@ -1,14 +1,25 @@ /* Memory configuration */ +#if MICROPY_HW_FLASH_RESERVED +reserved_size = MICROPY_HW_FLASH_RESERVED; +#endif + +#if MICROPY_HW_FLASH_TYPE==qspi_nor flash_start = 0x60000000; +#elif MICROPY_HW_FLASH_TYPE==hyperflash +flash_start = 0x60000000; +#else +#error Unknown MICROPY_HW_FLASH_TYPE +#endif +flash_size = MICROPY_HW_FLASH_SIZE; flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); flash_config_start = flash_start; flash_config_size = 0x00001000; -ivt_start = 0x60001000; +ivt_start = flash_start + 0x00001000; ivt_size = 0x00001000; -interrupts_start = 0x60002000; +interrupts_start = flash_start + 0x00002000; interrupts_size = 0x00000400; -text_start = 0x60002400; -vfs_start = 0x60100000; +text_start = flash_start + 0x00002400; +vfs_start = flash_start + 0x00200000; text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); itcm_start = 0x00000000; @@ -18,11 +29,21 @@ dtcm_size = 0x00020000; ocrm_start = 0x20200000; ocrm_size = 0x00040000; +#ifdef MICROPY_HW_SDRAM_AVAIL +sdram_start = 0x80000000; +sdram_size = MICROPY_HW_SDRAM_SIZE; +#endif + /* 24kiB stack. */ __stack_size__ = 0x6000; _estack = __StackTop; _sstack = __StackLimit; +#ifdef MICROPY_HW_SDRAM_AVAIL +_gc_heap_start = ORIGIN(m_sdram); +_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); +#else /* Use second OCRAM bank for GC heap. */ _gc_heap_start = ORIGIN(m_ocrm); _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); +#endif diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld b/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld deleted file mode 100644 index f616178a9..000000000 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/MIMXRT1060_EVK.ld +++ /dev/null @@ -1 +0,0 @@ -flash_size = 64M; \ No newline at end of file diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/board.json b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json new file mode 100644 index 000000000..67a3818ee --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/board.json @@ -0,0 +1,27 @@ +{ + "deploy": [ + "../deploy_mimxrt.md" + ], + "docs": "", + "features": [ + "Ethernet", + "SDRAM", + "MicroSD", + "MicroUSB", + "Microphone", + "AudioCodec", + "SPDIF", + "CAN", + "Camera", + "OpenSDA", + "JLink" + ], + "images": [ + "X-MIMXRT1060-EVK-BOARD-BOTTOM.jpg" + ], + "mcu": "mimxrt", + "product": "MIMXRT1060_EVK", + "thumbnail": "", + "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1060-evaluation-kit:MIMXRT1060-EVK", + "vendor": "NXP" +} diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/board.md b/ports/mimxrt/boards/MIMXRT1060_EVK/board.md new file mode 100644 index 000000000..5bca8d57f --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/board.md @@ -0,0 +1 @@ +The port for this board is experimental. It is made based on the documentation, but was not yet tested. \ No newline at end of file diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1060_EVK/clock_config.h new file mode 100644 index 000000000..082202484 --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/clock_config.h @@ -0,0 +1,122 @@ +/* + * Copyright 2018-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */ +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockRUN configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */ + +/* Clock outputs (values are in Hz): */ +#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL +#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL +#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL +#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL +#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL +#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL +#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL +#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL +#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL +#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL +#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL +#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL +#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL +#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL +#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL +#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL +#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL +#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL +#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL + +/*! @brief Arm PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN; +/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN; +/*! @brief Sys PLL for BOARD_BootClockRUN configuration. + */ +extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN; + +/******************************************************************************* + * API for BOARD_BootClockRUN configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockRUN(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h deleted file mode 100644 index cff520e0e..000000000 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/evkmimxrt1060_flexspi_nor_config.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ -#define __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ - -#include -#include -#include "fsl_flexspi.h" - -/*! @name Driver version */ -/*@{*/ -/*! @brief XIP_BOARD driver version 2.0.0. */ -#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) -/*@}*/ - -/* FLEXSPI memory config block related defintions */ -#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian -#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 -#define FLEXSPI_CFG_BLK_SIZE (512) - -/* FLEXSPI Feature related definitions */ -#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 - -/* Lookup table related defintions */ -#define CMD_INDEX_READ 0 -#define CMD_INDEX_READSTATUS 1 -#define CMD_INDEX_WRITEENABLE 2 -#define CMD_INDEX_WRITE 4 - -#define CMD_LUT_SEQ_IDX_READ 0 -#define CMD_LUT_SEQ_IDX_READSTATUS 1 -#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define CMD_LUT_SEQ_IDX_WRITE 9 - -#define CMD_SDR 0x01 -#define CMD_DDR 0x21 -#define RADDR_SDR 0x02 -#define RADDR_DDR 0x22 -#define CADDR_SDR 0x03 -#define CADDR_DDR 0x23 -#define MODE1_SDR 0x04 -#define MODE1_DDR 0x24 -#define MODE2_SDR 0x05 -#define MODE2_DDR 0x25 -#define MODE4_SDR 0x06 -#define MODE4_DDR 0x26 -#define MODE8_SDR 0x07 -#define MODE8_DDR 0x27 -#define WRITE_SDR 0x08 -#define WRITE_DDR 0x28 -#define READ_SDR 0x09 -#define READ_DDR 0x29 -#define LEARN_SDR 0x0A -#define LEARN_DDR 0x2A -#define DATSZ_SDR 0x0B -#define DATSZ_DDR 0x2B -#define DUMMY_SDR 0x0C -#define DUMMY_DDR 0x2C -#define DUMMY_RWDS_SDR 0x0D -#define DUMMY_RWDS_DDR 0x2D -#define JMP_ON_CS 0x1F -#define STOP 0 - -#define FLEXSPI_1PAD 0 -#define FLEXSPI_2PAD 1 -#define FLEXSPI_4PAD 2 -#define FLEXSPI_8PAD 3 - -#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ - (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ - FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) - -//!@brief Definitions for FlexSPI Serial Clock Frequency -typedef enum _FlexSpiSerialClockFreq -{ - kFlexSpiSerialClk_30MHz = 1, - kFlexSpiSerialClk_50MHz = 2, - kFlexSpiSerialClk_60MHz = 3, - kFlexSpiSerialClk_75MHz = 4, - kFlexSpiSerialClk_80MHz = 5, - kFlexSpiSerialClk_100MHz = 6, - kFlexSpiSerialClk_120MHz = 7, - kFlexSpiSerialClk_133MHz = 8, - kFlexSpiSerialClk_166MHz = 9, -} flexspi_serial_clk_freq_t; - -//!@brief FlexSPI clock configuration type -enum -{ - kFlexSpiClk_SDR, //!< Clock configure for SDR mode - kFlexSpiClk_DDR, //!< Clock configurat for DDR mode -}; - -//!@brief FlexSPI Read Sample Clock Source definition -typedef enum _FlashReadSampleClkSource -{ - kFlexSPIReadSampleClk_LoopbackInternally = 0, - kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, - kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, - kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, -} flexspi_read_sample_clk_t; - -//!@brief Misc feature bit definitions -enum -{ - kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable - kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable - kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable - kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable - kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable - kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable - kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. -}; - -//!@brief Flash Type Definition -enum -{ - kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR - kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND - kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH - kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND - kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs -}; - -//!@brief Flash Pad Definitions -enum -{ - kSerialFlash_1Pad = 1, - kSerialFlash_2Pads = 2, - kSerialFlash_4Pads = 4, - kSerialFlash_8Pads = 8, -}; - -//!@brief FlexSPI LUT Sequence structure -typedef struct _lut_sequence -{ - uint8_t seqNum; //!< Sequence Number, valid number: 1-16 - uint8_t seqId; //!< Sequence Index, valid number: 0-15 - uint16_t reserved; -} flexspi_lut_seq_t; - -//!@brief Flash Configuration Command Type -enum -{ - kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc - kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command - kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode - kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode - kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode - kDeviceConfigCmdType_Reset, //!< Reset device command -}; - -//!@brief FlexSPI Memory Configuration Block -typedef struct _FlexSPIConfig -{ - uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL - uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix - uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use - uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 - uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 - uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 - uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For - //! Serial NAND, need to refer to datasheet - uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable - uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, - //! Generic configuration, etc. - uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for - //! DPI/QPI/OPI switch or reset command - flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt - //! sequence number, [31:16] Reserved - uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration - uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable - uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe - flexspi_lut_seq_t - configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq - uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use - uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands - uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use - uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more - //! details - uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details - uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal - uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot - //! Chapter for more details - uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot - //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH - uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use - uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 - uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 - uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 - uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 - uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value - uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value - uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value - uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value - uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command - uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands - uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns - uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 - uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - - //! busy flag is 0 when flash device is busy - uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences - flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences - uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use -} flexspi_mem_config_t; - -/* */ -#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 -#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 -#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 -#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 -#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 -#define NOR_CMD_LUT_SEQ_IDX_READID 8 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 -#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 -#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 -#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 - -#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS 2 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP 12 - -/* - * Serial NOR configuration block - */ -typedef struct _flexspi_nor_config -{ - flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI - uint32_t pageSize; //!< Page size of Serial NOR - uint32_t sectorSize; //!< Sector size of Serial NOR - uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command - uint8_t isUniformBlockSize; //!< Sector/Block size is the same - uint8_t reserved0[2]; //!< Reserved for future use - uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 - uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command - uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false - uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution - uint32_t blockSize; //!< Block size - uint32_t reserve2[11]; //!< Reserved for future use -} flexspi_nor_config_t; - -#define FLASH_BUSY_STATUS_POL 0 -#define FLASH_BUSY_STATUS_OFFSET 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif -#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c deleted file mode 100644 index e28f58154..000000000 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/flash_config.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "evkmimxrt1060_flexspi_nor_config.h" - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.xip_board" -#endif - -/******************************************************************************* - * Code - ******************************************************************************/ -#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) -#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) -__attribute__((section(".boot_hdr.conf"))) -#elif defined(__ICCARM__) -#pragma location = ".boot_hdr.conf" -#endif - -const flexspi_nor_config_t qspiflash_config = { - .memConfig = - { - .tag = FLEXSPI_CFG_BLK_TAG, - .version = FLEXSPI_CFG_BLK_VERSION, - .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad, - .csHoldTime = 3u, - .csSetupTime = 3u, - .columnAddressWidth = 3u, - // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock - .controllerMiscOption = - (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) | - (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable), - .sflashPadType = kSerialFlash_8Pads, - .serialClkFreq = kFlexSpiSerialClk_133MHz, - .sflashA1Size = 64u * 1024u * 1024u, - .dataValidTime = {16u, 16u}, - .lookupTable = - { - /* 0 Read Data */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04), - - /* 1 Write Data */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02), - - /* 2 Read Status */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70 - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), - - /* 4 Write Enable */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - - /* 6 Erase Sector */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80 - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - // +2 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - // +3 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), - - /* 10 program page with word program command sequence */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0 - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80), - - /* 12 Erase chip */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - // +2 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - // +3 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10), - }, - }, - .pageSize = 512u, - .sectorSize = 256u * 1024u, - .blockSize = 256u * 1024u, - .isUniformBlockSize = true, -}; - -#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h index c207da832..b108122ff 100644 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h @@ -1,28 +1,25 @@ #define MICROPY_HW_BOARD_NAME "i.MX RT1060 EVK" #define MICROPY_HW_MCU_NAME "MIMXRT1062DVJ6A" -#define BOARD_FLASH_SIZE (8 * 1024 * 1024) - // MIMXRT1060_EVK has 1 user LED #define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09) #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) -#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1060_flexspi_nor_config.h" -#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_hyper_flash.h" #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) // Define mapping logical UART # to hardware UART # -// LPUART3 on D0/D1 -> 1 -// LPUART2 on D7/D6 -> 2 -// LPUART6 on D8/D9 -> 3 -// LPUART8 on A1/A0 -> 4 +// LPUART1 on USB_DBG -> 0 +// LPUART3 on D0/D1 -> 1 +// LPUART2 on D7/D6 -> 2 +// LPUART6 on D8/D9 -> 3 +// LPUART8 on A1/A0 -> 4 #define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) -#define MICROPY_HW_UART_INDEX { 0, 3, 2, 6, 8 } +#define MICROPY_HW_UART_INDEX { 1, 3, 2, 6, 8 } #define IOMUX_TABLE_UART \ - { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \ { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \ { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \ { 0 }, { 0 }, \ @@ -38,10 +35,10 @@ { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI }, #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \ - kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } + kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ - kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } // Define the mapping hardware I2C # to logical I2C # // SDA/SCL HW-I2C Logical I2C @@ -54,3 +51,81 @@ { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, + +#define USDHC_DUMMY_PIN NULL, 0 +#define MICROPY_USDHC1 \ + { \ + .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \ + .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \ + .cd_b = { GPIO_B1_12_USDHC1_CD_B }, \ + .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \ + .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \ + .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \ + .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \ + } + +// --- SEMC --- // +#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00 +#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01 +#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02 +#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03 +#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04 +#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05 +#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06 +#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07 +#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_30_SEMC_DATA08 +#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_31_SEMC_DATA09 +#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_32_SEMC_DATA10 +#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_33_SEMC_DATA11 +#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_34_SEMC_DATA12 +#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_35_SEMC_DATA13 +#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_36_SEMC_DATA14 +#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_37_SEMC_DATA15 + +#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_09_SEMC_ADDR00 +#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_10_SEMC_ADDR01 +#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_11_SEMC_ADDR02 +#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_12_SEMC_ADDR03 +#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_13_SEMC_ADDR04 +#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_14_SEMC_ADDR05 +#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_15_SEMC_ADDR06 +#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_16_SEMC_ADDR07 +#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_17_SEMC_ADDR08 +#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_18_SEMC_ADDR09 +#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_23_SEMC_ADDR10 +#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_19_SEMC_ADDR11 +#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_20_SEMC_ADDR12 + +#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_21_SEMC_BA0 +#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_22_SEMC_BA1 +#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_24_SEMC_CAS +#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_27_SEMC_CKE +#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_26_SEMC_CLK +#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00 +#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_38_SEMC_DM01 +#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_39_SEMC_DQS +#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_25_SEMC_RAS +#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE + +#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0 + +// Network definitions +// Transceiver Phy Address +#define ENET_PHY_ADDRESS (2) +#define ENET_PHY_OPS phyksz8081_ops + +// Etherner PIN definitions +#define ENET_RESET_PIN pin_GPIO_AD_B0_09 +#define ENET_INT_PIN pin_GPIO_AD_B0_10 + +#define IOMUX_TABLE_ENET \ + { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \ + { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u }, diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk index f5eaf3eab..56ccba6e5 100644 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk @@ -2,21 +2,26 @@ MCU_SERIES = MIMXRT1062 MCU_VARIANT = MIMXRT1062DVJ6A MICROPY_FLOAT_IMPL = double +MICROPY_PY_MACHINE_SDCARD = 1 +MICROPY_HW_FLASH_TYPE ?= qspi_nor +MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB -SRC_C += \ - hal/flexspi_hyper_flash.c \ +MICROPY_HW_SDRAM_AVAIL = 1 +MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB + +MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 JLINK_PATH ?= /media/RT1060-EVK/ JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink - ifdef JLINK_IP JLINK_CONNECTION_SETTINGS = -IP $(JLINK_IP) else JLINK_CONNECTION_SETTINGS = -USB endif - deploy_jlink: $(BUILD)/firmware.hex $(Q)$(TOUCH) $(JLINK_COMMANDER_SCRIPT) $(ECHO) "ExitOnError 1" > $(JLINK_COMMANDER_SCRIPT) diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/pins.csv b/ports/mimxrt/boards/MIMXRT1060_EVK/pins.csv index 366a141ff..463079b12 100644 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/pins.csv +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/pins.csv @@ -12,8 +12,8 @@ D10,GPIO_SD_B0_01 D11,GPIO_SD_B0_02 D12,GPIO_SD_B0_03 D13,GPIO_SD_B0_00 -D14,GPIO_AD_B1_01 -D15,GPIO_AD_B1_00 +D14,GPIO_AD_B0_01 +D15,GPIO_AD_B0_00 A0,GPIO_AD_B1_10 A1,GPIO_AD_B1_11 A2,GPIO_AD_B1_04 diff --git a/ports/mimxrt/boards/MIMXRT1062.ld b/ports/mimxrt/boards/MIMXRT1062.ld index 5edf70ee4..f588e5bd9 100644 --- a/ports/mimxrt/boards/MIMXRT1062.ld +++ b/ports/mimxrt/boards/MIMXRT1062.ld @@ -1,14 +1,25 @@ /* Memory configuration */ +#if MICROPY_HW_FLASH_RESERVED +reserved_size = MICROPY_HW_FLASH_RESERVED; +#endif + +#if MICROPY_HW_FLASH_TYPE==qspi_nor flash_start = 0x60000000; +#elif MICROPY_HW_FLASH_TYPE==hyperflash +flash_start = 0x60000000; +#else +#error Unknown MICROPY_HW_FLASH_TYPE +#endif +flash_size = MICROPY_HW_FLASH_SIZE; flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); flash_config_start = flash_start; flash_config_size = 0x00001000; -ivt_start = 0x60001000; +ivt_start = flash_start + 0x00001000; ivt_size = 0x00001000; -interrupts_start = 0x60002000; +interrupts_start = flash_start + 0x00002000; interrupts_size = 0x00000400; -text_start = 0x60002400; -vfs_start = 0x60100000; +text_start = flash_start + 0x00002400; +vfs_start = flash_start + 0x00100000; text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); itcm_start = 0x00000000; @@ -18,11 +29,21 @@ dtcm_size = 0x00020000; ocrm_start = 0x20200000; ocrm_size = 0x000C0000; +#ifdef MICROPY_HW_SDRAM_AVAIL +sdram_start = 0x80000000; +sdram_size = MICROPY_HW_SDRAM_SIZE; +#endif + /* 32kiB stack. */ __stack_size__ = 0x8000; _estack = __StackTop; _sstack = __StackLimit; +#ifdef MICROPY_HW_SDRAM_AVAIL +_gc_heap_start = ORIGIN(m_sdram); +_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); +#else /* Use second OCRAM bank for GC heap. */ _gc_heap_start = ORIGIN(m_ocrm); _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); +#endif diff --git a/ports/mimxrt/boards/MIMXRT1064.ld b/ports/mimxrt/boards/MIMXRT1064.ld index 820393001..b36c52845 100644 --- a/ports/mimxrt/boards/MIMXRT1064.ld +++ b/ports/mimxrt/boards/MIMXRT1064.ld @@ -1,14 +1,27 @@ /* Memory configuration */ +#if MICROPY_HW_FLASH_RESERVED +reserved_size = MICROPY_HW_FLASH_RESERVED; +#endif + +#if MICROPY_HW_FLASH_TYPE==qspi_nor flash_start = 0x60000000; +#elif MICROPY_HW_FLASH_TYPE==hyperflash +flash_start = 0x60000000; +#elif MICROPY_HW_FLASH_TYPE==internal +flash_start = 0x70000000; +#else +#error Unknown MICROPY_HW_FLASH_TYPE +#endif +flash_size = MICROPY_HW_FLASH_SIZE; flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size)); flash_config_start = flash_start; flash_config_size = 0x00001000; -ivt_start = 0x60001000; +ivt_start = flash_start + 0x00001000; ivt_size = 0x00001000; -interrupts_start = 0x60002000; +interrupts_start = flash_start + 0x00002000; interrupts_size = 0x00000400; -text_start = 0x60002400; -vfs_start = 0x60100000; +text_start = flash_start + 0x00002400; +vfs_start = flash_start + 0x00100000; text_size = ((vfs_start) - (text_start)); vfs_size = ((flash_end) - (vfs_start)); itcm_start = 0x00000000; @@ -18,11 +31,21 @@ dtcm_size = 0x00020000; ocrm_start = 0x20200000; ocrm_size = 0x000C0000; +#ifdef MICROPY_HW_SDRAM_AVAIL +sdram_start = 0x80000000; +sdram_size = MICROPY_HW_SDRAM_SIZE; +#endif + /* 24kiB stack. */ __stack_size__ = 0x6000; _estack = __StackTop; _sstack = __StackLimit; +#ifdef MICROPY_HW_SDRAM_AVAIL +_gc_heap_start = ORIGIN(m_sdram); +_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram); +#else /* Use second OCRAM bank for GC heap. */ _gc_heap_start = ORIGIN(m_ocrm); _gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm); +#endif diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld b/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld deleted file mode 100644 index f616178a9..000000000 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/MIMXRT1064_EVK.ld +++ /dev/null @@ -1 +0,0 @@ -flash_size = 64M; \ No newline at end of file diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/board.json b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json new file mode 100644 index 000000000..ef12336c4 --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/board.json @@ -0,0 +1,27 @@ +{ + "deploy": [ + "../deploy_mimxrt.md" + ], + "docs": "", + "features": [ + "Ethernet", + "SDRAM", + "MicroSD", + "MicroUSB", + "Microphone", + "AudioAmp", + "SPDIF", + "CAN", + "Camera", + "OpenSDA", + "JLink" + ], + "images": [ + "MIMXRT1064EVK-TOP.jpg" + ], + "mcu": "mimxrt", + "product": "MIMXRT1064_EVK", + "thumbnail": "", + "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1064-evaluation-kit:MIMXRT1064-EVK", + "vendor": "NXP" +} diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/board.md b/ports/mimxrt/boards/MIMXRT1064_EVK/board.md new file mode 100644 index 000000000..5bca8d57f --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/board.md @@ -0,0 +1 @@ +The port for this board is experimental. It is made based on the documentation, but was not yet tested. \ No newline at end of file diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/clock_config.h b/ports/mimxrt/boards/MIMXRT1064_EVK/clock_config.h new file mode 100644 index 000000000..13bc925a1 --- /dev/null +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/clock_config.h @@ -0,0 +1,122 @@ +/* + * Copyright 2018-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */ +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockRUN configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */ + +/* Clock outputs (values are in Hz): */ +#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL +#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL +#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL +#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL +#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL +#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL +#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL +#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL +#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 67500000UL +#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL +#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL +#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL +#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL +#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL +#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL +#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL +#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL +#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL +#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL + +/*! @brief Arm PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN; +/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN; +/*! @brief Sys PLL for BOARD_BootClockRUN configuration. + */ +extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN; + +/******************************************************************************* + * API for BOARD_BootClockRUN configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockRUN(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h b/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h deleted file mode 100644 index 7560f2483..000000000 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/evkmimxrt1064_flexspi_nor_config.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__ -#define __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__ - -#include -#include -#include "fsl_flexspi.h" - -/*! @name Driver version */ -/*@{*/ -/*! @brief XIP_BOARD driver version 2.0.0. */ -#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) -/*@}*/ - -/* FLEXSPI memory config block related defintions */ -#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian -#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 -#define FLEXSPI_CFG_BLK_SIZE (512) - -/* FLEXSPI Feature related definitions */ -#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 - -/* Lookup table related defintions */ -#define CMD_INDEX_READ 0 -#define CMD_INDEX_READSTATUS 1 -#define CMD_INDEX_WRITEENABLE 2 -#define CMD_INDEX_WRITE 4 - -#define CMD_LUT_SEQ_IDX_READ 0 -#define CMD_LUT_SEQ_IDX_READSTATUS 1 -#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define CMD_LUT_SEQ_IDX_WRITE 9 - -#define CMD_SDR 0x01 -#define CMD_DDR 0x21 -#define RADDR_SDR 0x02 -#define RADDR_DDR 0x22 -#define CADDR_SDR 0x03 -#define CADDR_DDR 0x23 -#define MODE1_SDR 0x04 -#define MODE1_DDR 0x24 -#define MODE2_SDR 0x05 -#define MODE2_DDR 0x25 -#define MODE4_SDR 0x06 -#define MODE4_DDR 0x26 -#define MODE8_SDR 0x07 -#define MODE8_DDR 0x27 -#define WRITE_SDR 0x08 -#define WRITE_DDR 0x28 -#define READ_SDR 0x09 -#define READ_DDR 0x29 -#define LEARN_SDR 0x0A -#define LEARN_DDR 0x2A -#define DATSZ_SDR 0x0B -#define DATSZ_DDR 0x2B -#define DUMMY_SDR 0x0C -#define DUMMY_DDR 0x2C -#define DUMMY_RWDS_SDR 0x0D -#define DUMMY_RWDS_DDR 0x2D -#define JMP_ON_CS 0x1F -#define STOP 0 - -#define FLEXSPI_1PAD 0 -#define FLEXSPI_2PAD 1 -#define FLEXSPI_4PAD 2 -#define FLEXSPI_8PAD 3 - -#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ - (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ - FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) - -//!@brief Definitions for FlexSPI Serial Clock Frequency -typedef enum _FlexSpiSerialClockFreq -{ - kFlexSpiSerialClk_30MHz = 1, - kFlexSpiSerialClk_50MHz = 2, - kFlexSpiSerialClk_60MHz = 3, - kFlexSpiSerialClk_75MHz = 4, - kFlexSpiSerialClk_80MHz = 5, - kFlexSpiSerialClk_100MHz = 6, - kFlexSpiSerialClk_120MHz = 7, - kFlexSpiSerialClk_133MHz = 8, - kFlexSpiSerialClk_166MHz = 9, -} flexspi_serial_clk_freq_t; - -//!@brief FlexSPI clock configuration type -enum -{ - kFlexSpiClk_SDR, //!< Clock configure for SDR mode - kFlexSpiClk_DDR, //!< Clock configurat for DDR mode -}; - -//!@brief FlexSPI Read Sample Clock Source definition -typedef enum _FlashReadSampleClkSource -{ - kFlexSPIReadSampleClk_LoopbackInternally = 0, - kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, - kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, - kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, -} flexspi_read_sample_clk_t; - -//!@brief Misc feature bit definitions -enum -{ - kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable - kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable - kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable - kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable - kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable - kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable - kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. -}; - -//!@brief Flash Type Definition -enum -{ - kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR - kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND - kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH - kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND - kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs -}; - -//!@brief Flash Pad Definitions -enum -{ - kSerialFlash_1Pad = 1, - kSerialFlash_2Pads = 2, - kSerialFlash_4Pads = 4, - kSerialFlash_8Pads = 8, -}; - -//!@brief FlexSPI LUT Sequence structure -typedef struct _lut_sequence -{ - uint8_t seqNum; //!< Sequence Number, valid number: 1-16 - uint8_t seqId; //!< Sequence Index, valid number: 0-15 - uint16_t reserved; -} flexspi_lut_seq_t; - -//!@brief Flash Configuration Command Type -enum -{ - kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc - kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command - kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode - kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode - kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode - kDeviceConfigCmdType_Reset, //!< Reset device command -}; - -//!@brief FlexSPI Memory Configuration Block -typedef struct _FlexSPIConfig -{ - uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL - uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix - uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use - uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 - uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 - uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 - uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For - //! Serial NAND, need to refer to datasheet - uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable - uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, - //! Generic configuration, etc. - uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for - //! DPI/QPI/OPI switch or reset command - flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt - //! sequence number, [31:16] Reserved - uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration - uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable - uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe - flexspi_lut_seq_t - configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq - uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use - uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands - uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use - uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more - //! details - uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details - uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal - uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot - //! Chapter for more details - uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot - //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH - uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use - uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 - uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 - uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 - uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 - uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value - uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value - uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value - uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value - uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command - uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands - uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns - uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 - uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - - //! busy flag is 0 when flash device is busy - uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences - flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences - uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use -} flexspi_mem_config_t; - -/* */ -#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 -#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 -#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 -#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 -#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 -#define NOR_CMD_LUT_SEQ_IDX_READID 8 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 -#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 -#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 -#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 - -#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS 2 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP 12 - -/* - * Serial NOR configuration block - */ -typedef struct _flexspi_nor_config -{ - flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI - uint32_t pageSize; //!< Page size of Serial NOR - uint32_t sectorSize; //!< Sector size of Serial NOR - uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command - uint8_t isUniformBlockSize; //!< Sector/Block size is the same - uint8_t reserved0[2]; //!< Reserved for future use - uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 - uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command - uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false - uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution - uint32_t blockSize; //!< Block size - uint32_t reserve2[11]; //!< Reserved for future use -} flexspi_nor_config_t; - -#define FLASH_BUSY_STATUS_POL 0 -#define FLASH_BUSY_STATUS_OFFSET 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif -#endif /* __EVKMIMXRT1064_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c b/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c deleted file mode 100644 index f308b7f8a..000000000 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/flash_config.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "evkmimxrt1064_flexspi_nor_config.h" - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.xip_board" -#endif - -/******************************************************************************* - * Code - ******************************************************************************/ -#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) -#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) -__attribute__((section(".boot_hdr.conf"))) -#elif defined(__ICCARM__) -#pragma location = ".boot_hdr.conf" -#endif - -const flexspi_nor_config_t qspiflash_config = { - .memConfig = - { - .tag = FLEXSPI_CFG_BLK_TAG, - .version = FLEXSPI_CFG_BLK_VERSION, - .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad, - .csHoldTime = 3u, - .csSetupTime = 3u, - .columnAddressWidth = 3u, - // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock - .controllerMiscOption = - (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) | - (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable), - .sflashPadType = kSerialFlash_8Pads, - .serialClkFreq = kFlexSpiSerialClk_133MHz, - .sflashA1Size = 64u * 1024u * 1024u, - .dataValidTime = {16u, 16u}, - .lookupTable = - { - /* 0 Read Data */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04), - - /* 1 Write Data */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02), - - /* 2 Read Status */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70 - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), - - /* 4 Write Enable */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - - /* 6 Erase Sector */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80 - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - // +2 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - // +3 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), - - /* 10 program page with word program command sequence */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0 - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ( - kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80), - - /* 12 Erase chip */ - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), - // +1 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - // +2 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), - // +3 - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), - [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] = - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10), - }, - }, - .pageSize = 512u, - .sectorSize = 256u * 1024u, - .blockSize = 256u * 1024u, - .isUniformBlockSize = true, -}; - -#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h index 59f28b0e2..3c724868f 100644 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h @@ -5,22 +5,21 @@ #define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09) #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) -#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1064_flexspi_nor_config.h" -#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_hyper_flash.h" #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) // Define mapping logical UART # to hardware UART # -// LPUART3 on D0/D1 -> 1 -// LPUART2 on D7/D6 -> 2 -// LPUART6 on D8/D9 -> 3 -// LPUART8 on A1/A0 -> 4 +// LPUART1 on USB_DBG -> 0 +// LPUART3 on D0/D1 -> 1 +// LPUART2 on D7/D6 -> 2 +// LPUART6 on D8/D9 -> 3 +// LPUART8 on A1/A0 -> 4 #define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) -#define MICROPY_HW_UART_INDEX { 0, 3, 2, 6, 8 } +#define MICROPY_HW_UART_INDEX { 1, 3, 2, 6, 8 } #define IOMUX_TABLE_UART \ - { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \ { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \ { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \ { 0 }, { 0 }, \ @@ -36,10 +35,10 @@ { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI }, #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \ - kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } + kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ - kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } // Define the mapping hardware I2C # to logical I2C # // SDA/SCL HW-I2C Logical I2C @@ -52,3 +51,81 @@ { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, + +#define USDHC_DUMMY_PIN NULL, 0 +#define MICROPY_USDHC1 \ + { \ + .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \ + .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \ + .cd_b = { GPIO_B1_12_USDHC1_CD_B }, \ + .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \ + .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \ + .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \ + .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \ + } + +// --- SEMC --- // +#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00 +#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01 +#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02 +#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03 +#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04 +#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05 +#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06 +#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07 +#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_30_SEMC_DATA08 +#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_31_SEMC_DATA09 +#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_32_SEMC_DATA10 +#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_33_SEMC_DATA11 +#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_34_SEMC_DATA12 +#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_35_SEMC_DATA13 +#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_36_SEMC_DATA14 +#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_37_SEMC_DATA15 + +#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_09_SEMC_ADDR00 +#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_10_SEMC_ADDR01 +#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_11_SEMC_ADDR02 +#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_12_SEMC_ADDR03 +#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_13_SEMC_ADDR04 +#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_14_SEMC_ADDR05 +#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_15_SEMC_ADDR06 +#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_16_SEMC_ADDR07 +#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_17_SEMC_ADDR08 +#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_18_SEMC_ADDR09 +#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_23_SEMC_ADDR10 +#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_19_SEMC_ADDR11 +#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_20_SEMC_ADDR12 + +#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_21_SEMC_BA0 +#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_22_SEMC_BA1 +#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_24_SEMC_CAS +#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_27_SEMC_CKE +#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_26_SEMC_CLK +#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00 +#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_38_SEMC_DM01 +#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_39_SEMC_DQS +#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_25_SEMC_RAS +#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE + +#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0 + +// Network definitions +// Transceiver Phy Address +#define ENET_PHY_ADDRESS (2) +#define ENET_PHY_OPS phyksz8081_ops + +// Etherner PIN definitions +#define ENET_RESET_PIN pin_GPIO_AD_B0_09 +#define ENET_INT_PIN pin_GPIO_AD_B0_10 + +#define IOMUX_TABLE_ENET \ + { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \ + { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u }, diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk index 444fe9967..5cd7d49ab 100644 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk @@ -2,13 +2,18 @@ MCU_SERIES = MIMXRT1064 MCU_VARIANT = MIMXRT1064DVL6A MICROPY_FLOAT_IMPL = double +MICROPY_PY_MACHINE_SDCARD = 1 +MICROPY_HW_FLASH_TYPE ?= hyperflash +MICROPY_HW_FLASH_SIZE ?= 0x4000000 # 64MB -SRC_C += \ - hal/flexspi_hyper_flash.c \ +MICROPY_HW_SDRAM_AVAIL = 1 +MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB + +MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 JLINK_PATH ?= /media/RT1064-EVK/ -CFLAGS += -DBOARD_FLASH_SIZE=0x400000 - deploy: $(BUILD)/firmware.bin cp $< $(JLINK_PATH) diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/pins.csv b/ports/mimxrt/boards/MIMXRT1064_EVK/pins.csv index 366a141ff..463079b12 100644 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/pins.csv +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/pins.csv @@ -12,8 +12,8 @@ D10,GPIO_SD_B0_01 D11,GPIO_SD_B0_02 D12,GPIO_SD_B0_03 D13,GPIO_SD_B0_00 -D14,GPIO_AD_B1_01 -D15,GPIO_AD_B1_00 +D14,GPIO_AD_B0_01 +D15,GPIO_AD_B0_00 A0,GPIO_AD_B1_10 A1,GPIO_AD_B1_11 A2,GPIO_AD_B1_04 diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/SEEED_ARCH_MIX_flexspi_nor_config.h b/ports/mimxrt/boards/SEEED_ARCH_MIX/SEEED_ARCH_MIX_flexspi_nor_config.h new file mode 100644 index 000000000..33698a34d --- /dev/null +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/SEEED_ARCH_MIX_flexspi_nor_config.h @@ -0,0 +1,258 @@ +/* + * Copyright 2019 NXP. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1020_flexspi_nor_config.h + +#ifndef __SEEED_ARCH_MIX_FLEXSPI_NOR_CONFIG__ +#define __SEEED_ARCH_MIX_FLEXSPI_NOR_CONFIG__ + +#include +#include +#include "fsl_common.h" + +/*! @name Driver version */ +/*@{*/ +/*! @brief XIP_BOARD driver version 2.0.0. */ +#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) +/*@}*/ + +/* FLEXSPI memory config block related defintions */ +#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian +#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 +#define FLEXSPI_CFG_BLK_SIZE (512) + +/* FLEXSPI Feature related definitions */ +#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 + +/* Lookup table related defintions */ +#define CMD_INDEX_READ 0 +#define CMD_INDEX_READSTATUS 1 +#define CMD_INDEX_WRITEENABLE 2 +#define CMD_INDEX_WRITE 4 + +#define CMD_LUT_SEQ_IDX_READ 0 +#define CMD_LUT_SEQ_IDX_READSTATUS 1 +#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 +#define CMD_LUT_SEQ_IDX_WRITE 9 + +#define CMD_SDR 0x01 +#define CMD_DDR 0x21 +#define RADDR_SDR 0x02 +#define RADDR_DDR 0x22 +#define CADDR_SDR 0x03 +#define CADDR_DDR 0x23 +#define MODE1_SDR 0x04 +#define MODE1_DDR 0x24 +#define MODE2_SDR 0x05 +#define MODE2_DDR 0x25 +#define MODE4_SDR 0x06 +#define MODE4_DDR 0x26 +#define MODE8_SDR 0x07 +#define MODE8_DDR 0x27 +#define WRITE_SDR 0x08 +#define WRITE_DDR 0x28 +#define READ_SDR 0x09 +#define READ_DDR 0x29 +#define LEARN_SDR 0x0A +#define LEARN_DDR 0x2A +#define DATSZ_SDR 0x0B +#define DATSZ_DDR 0x2B +#define DUMMY_SDR 0x0C +#define DUMMY_DDR 0x2C +#define DUMMY_RWDS_SDR 0x0D +#define DUMMY_RWDS_DDR 0x2D +#define JMP_ON_CS 0x1F +#define STOP 0 + +#define FLEXSPI_1PAD 0 +#define FLEXSPI_2PAD 1 +#define FLEXSPI_4PAD 2 +#define FLEXSPI_8PAD 3 + +#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ + FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) + +// !@brief Definitions for FlexSPI Serial Clock Frequency +typedef enum _FlexSpiSerialClockFreq +{ + kFlexSpiSerialClk_30MHz = 1, + kFlexSpiSerialClk_50MHz = 2, + kFlexSpiSerialClk_60MHz = 3, + kFlexSpiSerialClk_75MHz = 4, + kFlexSpiSerialClk_80MHz = 5, + kFlexSpiSerialClk_100MHz = 6, + kFlexSpiSerialClk_133MHz = 7, + kFlexSpiSerialClk_166MHz = 8, + kFlexSpiSerialClk_200MHz = 9, +} flexspi_serial_clk_freq_t; + +// !@brief FlexSPI clock configuration type +enum +{ + kFlexSpiClk_SDR, // !< Clock configure for SDR mode + kFlexSpiClk_DDR, // !< Clock configurat for DDR mode +}; + +// !@brief FlexSPI Read Sample Clock Source definition +typedef enum _FlashReadSampleClkSource +{ + kFlexSPIReadSampleClk_LoopbackInternally = 0, + kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, + kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, + kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, +} flexspi_read_sample_clk_t; + +// !@brief Misc feature bit definitions +enum +{ + kFlexSpiMiscOffset_DiffClkEnable = 0, // !< Bit for Differential clock enable + kFlexSpiMiscOffset_Ck2Enable = 1, // !< Bit for CK2 enable + kFlexSpiMiscOffset_ParallelEnable = 2, // !< Bit for Parallel mode enable + kFlexSpiMiscOffset_WordAddressableEnable = 3, // !< Bit for Word Addressable enable + kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, // !< Bit for Safe Configuration Frequency enable + kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable + kFlexSpiMiscOffset_DdrModeEnable = 6, // !< Bit for DDR clock confiuration indication. +}; + +// !@brief Flash Type Definition +enum +{ + kFlexSpiDeviceType_SerialNOR = 1, // !< Flash devices are Serial NOR + kFlexSpiDeviceType_SerialNAND = 2, // !< Flash devices are Serial NAND + kFlexSpiDeviceType_SerialRAM = 3, // !< Flash devices are Serial RAM/HyperFLASH + kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND + kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs +}; + +// !@brief Flash Pad Definitions +enum +{ + kSerialFlash_1Pad = 1, + kSerialFlash_2Pads = 2, + kSerialFlash_4Pads = 4, + kSerialFlash_8Pads = 8, +}; + +// !@brief FlexSPI LUT Sequence structure +typedef struct _lut_sequence +{ + uint8_t seqNum; // !< Sequence Number, valid number: 1-16 + uint8_t seqId; // !< Sequence Index, valid number: 0-15 + uint16_t reserved; +} flexspi_lut_seq_t; + +// !@brief Flash Configuration Command Type +enum +{ + kDeviceConfigCmdType_Generic, // !< Generic command, for example: configure dummy cycles, drive strength, etc + kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command + kDeviceConfigCmdType_Spi2Xpi, // !< Switch from SPI to DPI/QPI/OPI mode + kDeviceConfigCmdType_Xpi2Spi, // !< Switch from DPI/QPI/OPI to SPI mode + kDeviceConfigCmdType_Spi2NoCmd, // !< Switch to 0-4-4/0-8-8 mode + kDeviceConfigCmdType_Reset, // !< Reset device command +}; + +// !@brief FlexSPI Memory Configuration Block +typedef struct _FlexSPIConfig +{ + uint32_t tag; // !< [0x000-0x003] Tag, fixed value 0x42464346UL + uint32_t version; // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix + uint32_t reserved0; // !< [0x008-0x00b] Reserved for future use + uint8_t readSampleClkSrc; // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 + uint8_t csHoldTime; // !< [0x00d-0x00d] CS hold time, default value: 3 + uint8_t csSetupTime; // !< [0x00e-0x00e] CS setup time, default value: 3 + uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For + // ! Serial NAND, need to refer to datasheet + uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable + uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, + // ! Generic configuration, etc. + uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for + // ! DPI/QPI/OPI switch or reset command + flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt + // ! sequence number, [31:16] Reserved + uint32_t deviceModeArg; // !< [0x018-0x01b] Argument/Parameter for device configuration + uint8_t configCmdEnable; // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable + uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe + flexspi_lut_seq_t + configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq + uint32_t reserved1; // !< [0x02c-0x02f] Reserved for future use + uint32_t configCmdArgs[3]; // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands + uint32_t reserved2; // !< [0x03c-0x03f] Reserved for future use + uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more + // ! details + uint8_t deviceType; // !< [0x044-0x044] Device Type: See Flash Type Definition for more details + uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal + uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot + // ! Chapter for more details + uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot + // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH + uint32_t reserved3[2]; // !< [0x048-0x04f] Reserved for future use + uint32_t sflashA1Size; // !< [0x050-0x053] Size of Flash connected to A1 + uint32_t sflashA2Size; // !< [0x054-0x057] Size of Flash connected to A2 + uint32_t sflashB1Size; // !< [0x058-0x05b] Size of Flash connected to B1 + uint32_t sflashB2Size; // !< [0x05c-0x05f] Size of Flash connected to B2 + uint32_t csPadSettingOverride; // !< [0x060-0x063] CS pad setting override value + uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value + uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value + uint32_t dqsPadSettingOverride; // !< [0x06c-0x06f] DQS pad setting override value + uint32_t timeoutInMs; // !< [0x070-0x073] Timeout threshold for read status command + uint32_t commandInterval; // !< [0x074-0x077] CS deselect interval between two commands + uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns + uint16_t busyOffset; // !< [0x07c-0x07d] Busy offset, valid value: 0-31 + uint16_t busyBitPolarity; // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - + // ! busy flag is 0 when flash device is busy + uint32_t lookupTable[64]; // !< [0x080-0x17f] Lookup table holds Flash command sequences + flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences + uint32_t reserved4[4]; // !< [0x1b0-0x1bf] Reserved for future use +} flexspi_mem_config_t; + +/* */ +#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 +#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 +#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 +#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 +#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 +#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 +#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 +#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 +#define NOR_CMD_LUT_SEQ_IDX_READID 8 +#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 +#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 +#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 +#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 + +/* + * Serial NOR configuration block + */ +typedef struct _flexspi_nor_config +{ + flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI + uint32_t pageSize; // !< Page size of Serial NOR + uint32_t sectorSize; // !< Sector size of Serial NOR + uint8_t ipcmdSerialClkFreq; // !< Clock frequency for IP command + uint8_t isUniformBlockSize; // !< Sector/Block size is the same + uint8_t reserved0[2]; // !< Reserved for future use + uint8_t serialNorType; // !< Serial NOR Flash type: 0/1/2/3 + uint8_t needExitNoCmdMode; // !< Need to exit NoCmd mode before other IP command + uint8_t halfClkForNonReadCmd; // !< Half the Serial Clock for non-read command: true/false + uint8_t needRestoreNoCmdMode; // !< Need to Restore NoCmd mode after IP commmand execution + uint32_t blockSize; // !< Block size + uint32_t reserve2[11]; // !< Reserved for future use +} flexspi_nor_config_t; + +#define FLASH_BUSY_STATUS_POL 0 +#define FLASH_BUSY_STATUS_OFFSET 0 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif +#endif /* __SEEED_ARCH_MIX_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json b/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json new file mode 100644 index 000000000..3142f1a81 --- /dev/null +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/board.json @@ -0,0 +1,20 @@ +{ + "deploy": [ + "deploy.md" + ], + "docs": "", + "features": [ + "MicroSD", + "MicroUSB", + "SDRAM", + "RGB LED" + ], + "images": [ + "main1.jpg" + ], + "mcu": "mimxrt", + "product": "Arch Mix", + "thumbnail": "", + "url": "https://wiki.seeedstudio.com/Arch_Mix/", + "vendor": "Seeed Technology Co.,Ltd." +} diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/clock_config.h b/ports/mimxrt/boards/SEEED_ARCH_MIX/clock_config.h new file mode 100644 index 000000000..f213ac7e2 --- /dev/null +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/clock_config.h @@ -0,0 +1,119 @@ +/* + * Copyright 2017-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */ +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockRUN configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */ + +/* Clock outputs (values are in Hz): */ +#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL +#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL +#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL +#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL +#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL +#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL +#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 160000000UL +#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL +#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL +#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL +#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL +#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL +#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL +#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL +#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL +#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL +#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL +#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL +#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL + +/*! @brief Arm PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN; +/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN; +/*! @brief Sys PLL for BOARD_BootClockRUN configuration. + */ +extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN; + +/******************************************************************************* + * API for BOARD_BootClockRUN configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockRUN(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/deploy.md b/ports/mimxrt/boards/SEEED_ARCH_MIX/deploy.md new file mode 100644 index 000000000..e91c48d46 --- /dev/null +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/deploy.md @@ -0,0 +1,6 @@ +Firmware upload to the Seed ARCH MIX board can be done using the J-Link interface +For that, follow the instructions given by Seed in their Wiki at +https://wiki.seeedstudio.com/Arch_Mix/#flashing-arduino-bootloader-to-arch-mix. +You will need a J-Link debug probe and software. What has been tested was the +Segger JLlink edu or Segger JLink edu mini. As matching loader tool you can use +Segger JFlashLite. The target address for loading is 0x60000000. diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h new file mode 100644 index 000000000..7c79063ee --- /dev/null +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h @@ -0,0 +1,142 @@ +#define MICROPY_HW_BOARD_NAME "Seeed ARCH MIX" +#define MICROPY_HW_MCU_NAME "MIMXRT1052DVL5B" + +// MIMXRT1050_EVKB has 1 user LED +#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09) +#define MICROPY_HW_LED2_PIN (pin_GPIO_AD_B0_10) +#define MICROPY_HW_LED3_PIN (pin_GPIO_AD_B0_11) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) + +#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) + +// Define mapping logical UART # to hardware UART # +// LPUART1 on J3_19/J3_20 -> 1 +// LPUART2 on J4_16/J4_17 -> 2 +// LPUART3 on J4_06/J4_07 -> 3 +// LPUART8 on J4_10/J4_11 -> 4 +// LPUART4 on J5_08/J5_12 -> 5 + +#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) +#define MICROPY_HW_UART_INDEX { 0, 1, 2, 3, 8, 4 } + +#define IOMUX_TABLE_UART \ + { IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \ + { IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \ + { IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \ + { IOMUXC_GPIO_B1_00_LPUART4_TX }, { IOMUXC_GPIO_B1_01_LPUART4_RX }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX }, + +#define MICROPY_HW_SPI_INDEX { 3, 4 } + +#define IOMUX_TABLE_SPI \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { 0 }, { 0 }, \ + { IOMUXC_GPIO_AD_B1_15_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B1_12_LPSPI3_PCS0 }, \ + { IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_13_LPSPI3_SDI }, \ + { IOMUXC_GPIO_B1_07_LPSPI4_SCK }, { IOMUXC_GPIO_B1_04_LPSPI4_PCS0 }, \ + { IOMUXC_GPIO_B1_06_LPSPI4_SDO }, { IOMUXC_GPIO_B1_05_LPSPI4_SDI }, + +#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \ + kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } + +#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ + kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + +// Define the mapping hardware I2C # to logical I2C # +// SDA/SCL HW-I2C Logical I2C +// J3_17/J3_16 LPI2C1 -> 0 +// J4_06/J4_07 LPI2C3 -> 1 +// J5_05/J5_04 LPI2C2 -> 2 + +#define MICROPY_HW_I2C_INDEX { 1, 3, 2 } + +#define IOMUX_TABLE_I2C \ + { IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL }, { IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA }, \ + { IOMUXC_GPIO_B0_04_LPI2C2_SCL }, { IOMUXC_GPIO_B0_05_LPI2C2_SDA }, \ + { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA } + +#define USDHC_DUMMY_PIN NULL, 0 + +#define MICROPY_USDHC1 \ + { \ + .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \ + .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \ + .cd_b = { GPIO_B1_12_USDHC1_CD_B }, \ + .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \ + .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \ + .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \ + .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \ + } + +// Network definitions +// Transceiver Phy Address & Type +#define ENET_PHY_ADDRESS (1) +#define ENET_PHY LAN8720 +#define ENET_PHY_OPS phylan8720_ops +#define ENET_TX_CLK_OUTPUT false + +// Etherner PIN definitions +// No reset and interrupt pin by intention + +#define IOMUX_TABLE_ENET \ + { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \ + { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0x30E9u }, \ + { IOMUXC_GPIO_EMC_41_ENET_MDIO, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_EMC_40_ENET_MDC, 0, 0xB0E9u }, + +// --- SEMC --- // +#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_00_SEMC_DATA00 +#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_01_SEMC_DATA01 +#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_02_SEMC_DATA02 +#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_03_SEMC_DATA03 +#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_04_SEMC_DATA04 +#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_05_SEMC_DATA05 +#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_06_SEMC_DATA06 +#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_07_SEMC_DATA07 +#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_30_SEMC_DATA08 +#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_31_SEMC_DATA09 +#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_32_SEMC_DATA10 +#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_33_SEMC_DATA11 +#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_34_SEMC_DATA12 +#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_35_SEMC_DATA13 +#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_36_SEMC_DATA14 +#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_37_SEMC_DATA15 + +#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_09_SEMC_ADDR00 +#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_10_SEMC_ADDR01 +#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_11_SEMC_ADDR02 +#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_12_SEMC_ADDR03 +#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_13_SEMC_ADDR04 +#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_14_SEMC_ADDR05 +#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_15_SEMC_ADDR06 +#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_16_SEMC_ADDR07 +#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_17_SEMC_ADDR08 +#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_18_SEMC_ADDR09 +#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_23_SEMC_ADDR10 +#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_19_SEMC_ADDR11 +#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_20_SEMC_ADDR12 + +#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_21_SEMC_BA0 +#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_22_SEMC_BA1 +#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_24_SEMC_CAS +#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_27_SEMC_CKE +#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_26_SEMC_CLK +#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_08_SEMC_DM00 +#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_38_SEMC_DM01 +#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_39_SEMC_DQS +#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_25_SEMC_RAS +#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_28_SEMC_WE + +#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_29_SEMC_CS0 diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk new file mode 100644 index 000000000..90edc5d51 --- /dev/null +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk @@ -0,0 +1,14 @@ +MCU_SERIES = MIMXRT1052 +MCU_VARIANT = MIMXRT1052DVL6B + +MICROPY_FLOAT_IMPL = double +MICROPY_PY_MACHINE_SDCARD = 1 +MICROPY_HW_FLASH_TYPE ?= qspi_nor +MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB + +MICROPY_HW_SDRAM_AVAIL = 1 +MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB + +MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/pins.csv b/ports/mimxrt/boards/SEEED_ARCH_MIX/pins.csv new file mode 100644 index 000000000..0183795cd --- /dev/null +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/pins.csv @@ -0,0 +1,62 @@ +J3_04,GPIO_B1_11 +J3_05,GPIO_B1_06 +J3_06,GPIO_EMC_41 +J3_07,GPIO_EMC_40 +J3_08,GPIO_B1_05 +J3_09,GPIO_B1_04 +J3_10,GPIO_B1_08 +J3_11,GPIO_B1_07 +J3_12,GPIO_B1_09 +J3_13,GPIO_B1_10 +J3_14,GPIO_AD_B0_14 +J3_15,GPO_AD_B0_15 +J3_16,GPIO_AD_B1_00 +J3_17,GPIO_AD_B1_01 +J3_19,GPIO_AD_B0_13 +J3_20,GPIO_AD_B0_12 +J4_04,GPIO_AD_B1_04 +J4_05,GPIO_AD_B1_05 +J4_06,GPIO_AD_B1_06 +J4_07,GPIO_AD_B1_07 +J4_08,GPIO_AD_B1_08 +J4_09,GPIO_AD_B1_09 +J4_10,GPIO_AD_B1_10 +J4_11,GPIO_AD_B1_11 +J4_12,GPIO_AD_B1_12 +J4_13,GPIO_AD_B1_13 +J4_14,GPIO_AD_B1_14 +J4_15,GPIO_AD_B1_15 +J4_16,GPIO_AD_B1_02 +J4_17,GPIO_AD_B1_03 +J4_19,GPIO_AD_B0_07 +J4_20,GPIO_AD_B0_06 +J5_32,GPIO_B0_00 +J5_28,GPIO_B0_01 +J5_29,GPIO_B0_02 +J5_30,GPIO_B0_03 +J5_04,GPIO_B0_04 +J5_05,GPIO_B0_05 +J5_06,GPIO_B0_06 +J5_07,GPIO_B0_07 +J5_08,GPIO_B0_08 +J5_12,GPIO_B0_09 +J5_13,GPIO_B0_10 +J5_14,GPIO_B0_11 +J5_15,GPIO_B0_12 +J5_16,GPIO_B0_13 +J5_17,GPIO_B0_14 +J5_22,GPIO_B0_15 +J5_23,GPIO_B1_00 +J5_24,GPIO_B1_01 +J5_25,GPIO_B1_02 +J5_26,GPIO_B1_03 +J5_34,GPIO_AD_B1_15 +J5_35,GPIO_AD_B1_14 +J5_36,GPIO_AD_B1_13 +J5_37,GPIO_AD_B1_12 +J5_42,GPIO_AD_B1_00 +J5_43,GPIO_AD_B1_01 +J5_50,GPIO_AD_B0_02 +LED_RED,GPIO_AD_B0_09 +LED_GREEN,GPIO_AD_B0_10 +LED_BLUE,GPIO_AD_B0_11 diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/qspi_nor_flash_config.c b/ports/mimxrt/boards/SEEED_ARCH_MIX/qspi_nor_flash_config.c new file mode 100644 index 000000000..7b2584d3d --- /dev/null +++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/qspi_nor_flash_config.c @@ -0,0 +1,136 @@ +/* + * Copyright 2019 NXP. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c + +#include BOARD_FLASH_CONFIG_HEADER_H + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.xip_board" +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ +#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) +#if defined(__ARMCC_VERSION) || defined(__GNUC__) +__attribute__((section(".boot_hdr.conf"))) +#elif defined(__ICCARM__) +#pragma location = ".boot_hdr.conf" +#endif + +const flexspi_nor_config_t qspiflash_config = { + .memConfig = + { + .tag = FLEXSPI_CFG_BLK_TAG, + .version = FLEXSPI_CFG_BLK_VERSION, + .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad, + .csHoldTime = 3u, + .csSetupTime = 3u, + .busyOffset = FLASH_BUSY_STATUS_OFFSET, // Status bit 0 indicates busy. + .busyBitPolarity = FLASH_BUSY_STATUS_POL, // Busy when the bit is 1. + .deviceModeCfgEnable = 1u, + .deviceModeType = kDeviceConfigCmdType_QuadEnable, + .deviceModeSeq = { + .seqId = 4u, + .seqNum = 1u, + }, + .deviceModeArg = 0x40, + // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock + .deviceType = kFlexSpiDeviceType_SerialNOR, + .sflashPadType = kSerialFlash_4Pads, + .serialClkFreq = kFlexSpiSerialClk_100MHz, + .sflashA1Size = BOARD_FLASH_SIZE, + .lookupTable = + { + // 0 Read LUTs 0 -> 0 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), + FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 1 Read status register -> 1 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 2 Fast read quad mode - SDR + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 3 Write Enable -> 3 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 4 Read extend parameters + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 5 Erase Sector -> 5 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 6 Write Status Reg + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 7 Page Program - quad mode (-> 9) + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 8 Read ID + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 9 Page Program - single mode -> 9 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 10 Enter QPI mode + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 11 Erase Chip + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 12 Exit QPI mode + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + }, + }, + .pageSize = 256u, + .sectorSize = 4u * 1024u, + .blockSize = 256u * 1024u, + .isUniformBlockSize = false, + // .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz, +}; +#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/TEENSY40/TEENSY40.ld b/ports/mimxrt/boards/TEENSY40/TEENSY40.ld deleted file mode 100644 index a3b696db6..000000000 --- a/ports/mimxrt/boards/TEENSY40/TEENSY40.ld +++ /dev/null @@ -1,2 +0,0 @@ -flash_size = 2M; -reserved_size = 4K; \ No newline at end of file diff --git a/ports/mimxrt/boards/TEENSY40/board.json b/ports/mimxrt/boards/TEENSY40/board.json new file mode 100644 index 000000000..daa6dbf99 --- /dev/null +++ b/ports/mimxrt/boards/TEENSY40/board.json @@ -0,0 +1,17 @@ +{ + "deploy": [ + "../deploy_teensy.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly" + ], + "images": [ + "teensy40_front.jpg" + ], + "mcu": "mimxrt", + "product": "Teensy 4.0", + "thumbnail": "", + "url": "https://www.pjrc.com/store/teensy40.html", + "vendor": "PJRC" +} diff --git a/ports/mimxrt/boards/TEENSY40/clock_config.h b/ports/mimxrt/boards/TEENSY40/clock_config.h new file mode 100644 index 000000000..082202484 --- /dev/null +++ b/ports/mimxrt/boards/TEENSY40/clock_config.h @@ -0,0 +1,122 @@ +/* + * Copyright 2018-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */ +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockRUN configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */ + +/* Clock outputs (values are in Hz): */ +#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL +#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL +#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL +#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL +#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL +#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL +#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL +#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL +#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL +#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL +#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL +#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL +#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL +#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL +#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL +#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL +#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL +#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL +#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL + +/*! @brief Arm PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN; +/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN; +/*! @brief Sys PLL for BOARD_BootClockRUN configuration. + */ +extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN; + +/******************************************************************************* + * API for BOARD_BootClockRUN configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockRUN(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ diff --git a/ports/mimxrt/boards/TEENSY40/flash_config.c b/ports/mimxrt/boards/TEENSY40/flash_config.c deleted file mode 100644 index 7a63cf825..000000000 --- a/ports/mimxrt/boards/TEENSY40/flash_config.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.c - -#include "teensy40_flexspi_nor_config.h" - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.xip_board" -#endif - -/******************************************************************************* - * Code - ******************************************************************************/ -#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) -#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) -__attribute__((section(".boot_hdr.conf"))) -#elif defined(__ICCARM__) -#pragma location = ".boot_hdr.conf" -#endif - -const flexspi_nor_config_t qspiflash_config = { - .memConfig = - { - .tag = FLEXSPI_CFG_BLK_TAG, - .version = FLEXSPI_CFG_BLK_VERSION, - .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad, - .csHoldTime = 3u, - .csSetupTime = 3u, - - .busyOffset = FLASH_BUSY_STATUS_OFFSET, // Status bit 0 indicates busy. - .busyBitPolarity = FLASH_BUSY_STATUS_POL, // Busy when the bit is 1. - - .deviceModeCfgEnable = 1u, - .deviceModeType = kDeviceConfigCmdType_QuadEnable, - .deviceModeSeq = { - .seqId = 4u, - .seqNum = 1u, - }, - .deviceModeArg = 0x0200, - .configCmdEnable = 1u, - .configModeType[0] = kDeviceConfigCmdType_Generic, - .configCmdSeqs[0] = { - .seqId = 2u, - .seqNum = 1u, - }, - .deviceType = kFlexSpiDeviceType_SerialNOR, - // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock - .sflashPadType = kSerialFlash_4Pads, - .serialClkFreq = kFlexSpiSerialClk_60MHz, - .sflashA1Size = 2u * 1024u * 1024u, - .lookupTable = - { - // 0 Read LUTs 0 -> 0 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 1 Read status register -> 1 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 2 Fast read quad mode - SDR - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 3 Write Enable -> 3 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 4 Read extend parameters - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 5 Erase Sector -> 5 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 6 Write Status Reg - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 7 Page Program - quad mode (-> 9) - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 8 Read ID - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 9 Page Program - single mode -> 9 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 10 Enter QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 11 Erase Chip - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 12 Exit QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - }, - }, - .pageSize = 256u, - .sectorSize = 4u * 1024u, - .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz, - .blockSize = 0x00010000, - .isUniformBlockSize = false, -}; -#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h index aacee4623..ae0a23462 100644 --- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h +++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h @@ -1,14 +1,10 @@ #define MICROPY_HW_BOARD_NAME "Teensy 4.0" #define MICROPY_HW_MCU_NAME "MIMXRT1062DVJ6A" -#define BOARD_FLASH_SIZE (2 * 1024 * 1024) - // Teensy 4.0 has 1 board LED #define MICROPY_HW_LED1_PIN (pin_GPIO_B0_03) #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) -#define BOARD_FLASH_CONFIG_HEADER_H "teensy40_flexspi_nor_config.h" -#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h" #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) @@ -39,10 +35,10 @@ { IOMUXC_GPIO_B0_02_LPSPI4_SDO }, { IOMUXC_GPIO_B0_01_LPSPI4_SDI }, #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \ - kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } + kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ - kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } // Define mapping hardware I2C # to logical I2C # // SDA/SCL HW-I2C Logical I2C @@ -57,3 +53,15 @@ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, \ { IOMUXC_GPIO_AD_B0_12_LPI2C4_SCL }, { IOMUXC_GPIO_AD_B0_13_LPI2C4_SDA }, + +#define USDHC_DUMMY_PIN NULL, 0 +#define MICROPY_USDHC1 \ + { \ + .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \ + .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \ + .cd_b = { USDHC_DUMMY_PIN }, \ + .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \ + .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \ + .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \ + .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \ + } diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk index a15dd7812..94e427cc1 100644 --- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk +++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.mk @@ -2,9 +2,10 @@ MCU_SERIES = MIMXRT1062 MCU_VARIANT = MIMXRT1062DVJ6A MICROPY_FLOAT_IMPL = double - -SRC_C += \ - hal/flexspi_nor_flash.c \ +MICROPY_PY_MACHINE_SDCARD = 1 +MICROPY_HW_FLASH_TYPE ?= qspi_nor +MICROPY_HW_FLASH_SIZE ?= 0x200000 # 2MB +MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB deploy: $(BUILD)/firmware.hex teensy_loader_cli --mcu=imxrt1062 -v -w $< diff --git a/ports/mimxrt/boards/TEENSY40/pins.csv b/ports/mimxrt/boards/TEENSY40/pins.csv index c9d7c9856..0ea4f1373 100644 --- a/ports/mimxrt/boards/TEENSY40/pins.csv +++ b/ports/mimxrt/boards/TEENSY40/pins.csv @@ -32,12 +32,12 @@ D30,GPIO_EMC_37 D31,GPIO_EMC_36 D32,GPIO_B0_12 D33,GPIO_EMC_07 -DAT1,GPIO_AD_B0_03 -DAT0,GPIO_AD_B0_02 -CLK,GPIO_AD_B0_01 -CMD,GPIO_ASD_B0_00 -DAT3,GPIO_SD_B0_05 +CMD,GPIO_SD_B0_00 +CLK,GPIO_SD_B0_01 +DAT0,GPIO_SD_B0_02 +DAT1,GPIO_SD_B0_03 DAT2,GPIO_SD_B0_04 +DAT3,GPIO_SD_B0_05 A0,GPIO_AD_B1_02 A1,GPIO_AD_B1_03 A2,GPIO_AD_B1_07 diff --git a/ports/mimxrt/boards/TEENSY40/teensy40_flexspi_nor_config.h b/ports/mimxrt/boards/TEENSY40/teensy40_flexspi_nor_config.h deleted file mode 100644 index 445a0bacc..000000000 --- a/ports/mimxrt/boards/TEENSY40/teensy40_flexspi_nor_config.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.h - -#ifndef __TEENSY40_FLEXSPI_NOR_CONFIG__ -#define __TEENSY40_FLEXSPI_NOR_CONFIG__ - -#include -#include -#include "fsl_common.h" - -/*! @name Driver version */ -/*@{*/ -/*! @brief XIP_BOARD driver version 2.0.0. */ -#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) -/*@}*/ - -/* FLEXSPI memory config block related defintions */ -#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian -#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 -#define FLEXSPI_CFG_BLK_SIZE (512) - -/* FLEXSPI Feature related definitions */ -#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 - -/* Lookup table related definitions */ -#define CMD_INDEX_READ 0 -#define CMD_INDEX_READSTATUS 1 -#define CMD_INDEX_WRITEENABLE 2 -#define CMD_INDEX_WRITE 4 - -#define CMD_LUT_SEQ_IDX_READ 0 -#define CMD_LUT_SEQ_IDX_READSTATUS 1 -#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define CMD_LUT_SEQ_IDX_ERASE 5 -#define CMD_LUT_SEQ_IDX_WRITE 9 - -#define CMD_SDR 0x01 -#define CMD_DDR 0x21 -#define RADDR_SDR 0x02 -#define RADDR_DDR 0x22 -#define CADDR_SDR 0x03 -#define CADDR_DDR 0x23 -#define MODE1_SDR 0x04 -#define MODE1_DDR 0x24 -#define MODE2_SDR 0x05 -#define MODE2_DDR 0x25 -#define MODE4_SDR 0x06 -#define MODE4_DDR 0x26 -#define MODE8_SDR 0x07 -#define MODE8_DDR 0x27 -#define WRITE_SDR 0x08 -#define WRITE_DDR 0x28 -#define READ_SDR 0x09 -#define READ_DDR 0x29 -#define LEARN_SDR 0x0A -#define LEARN_DDR 0x2A -#define DATSZ_SDR 0x0B -#define DATSZ_DDR 0x2B -#define DUMMY_SDR 0x0C -#define DUMMY_DDR 0x2C -#define DUMMY_RWDS_SDR 0x0D -#define DUMMY_RWDS_DDR 0x2D -#define JMP_ON_CS 0x1F -#define STOP 0 - -#define FLEXSPI_1PAD 0 -#define FLEXSPI_2PAD 1 -#define FLEXSPI_4PAD 2 -#define FLEXSPI_8PAD 3 - -#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ - (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ - FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) - -//!@brief Definitions for FlexSPI Serial Clock Frequency -typedef enum _FlexSpiSerialClockFreq -{ - kFlexSpiSerialClk_30MHz = 1, - kFlexSpiSerialClk_50MHz = 2, - kFlexSpiSerialClk_60MHz = 3, - kFlexSpiSerialClk_75MHz = 4, - kFlexSpiSerialClk_80MHz = 5, - kFlexSpiSerialClk_100MHz = 6, - kFlexSpiSerialClk_120MHz = 7, - kFlexSpiSerialClk_133MHz = 8, - kFlexSpiSerialClk_166MHz = 9, -} flexspi_serial_clk_freq_t; - -//!@brief FlexSPI clock configuration type -enum -{ - kFlexSpiClk_SDR, //!< Clock configure for SDR mode - kFlexSpiClk_DDR, //!< Clock configurat for DDR mode -}; - -//!@brief FlexSPI Read Sample Clock Source definition -typedef enum _FlashReadSampleClkSource -{ - kFlexSPIReadSampleClk_LoopbackInternally = 0, - kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, - kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, - kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, -} flexspi_read_sample_clk_t; - -//!@brief Misc feature bit definitions -enum -{ - kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable - kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable - kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable - kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable - kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable - kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable - kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. -}; - -//!@brief Flash Type Definition -enum -{ - kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR - kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND - kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH - kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND - kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs -}; - -//!@brief Flash Pad Definitions -enum -{ - kSerialFlash_1Pad = 1, - kSerialFlash_2Pads = 2, - kSerialFlash_4Pads = 4, - kSerialFlash_8Pads = 8, -}; - -//!@brief FlexSPI LUT Sequence structure -typedef struct _lut_sequence -{ - uint8_t seqNum; //!< Sequence Number, valid number: 1-16 - uint8_t seqId; //!< Sequence Index, valid number: 0-15 - uint16_t reserved; -} flexspi_lut_seq_t; - -//!@brief Flash Configuration Command Type -enum -{ - kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc - kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command - kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode - kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode - kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode - kDeviceConfigCmdType_Reset, //!< Reset device command -}; - -//!@brief FlexSPI Memory Configuration Block -typedef struct _FlexSPIConfig -{ - uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL - uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix - uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use - uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 - uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 - uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 - uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For - //! Serial NAND, need to refer to datasheet - uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable - uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, - //! Generic configuration, etc. - uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for - //! DPI/QPI/OPI switch or reset command - flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt - //! sequence number, [31:16] Reserved - uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration - uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable - uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe - flexspi_lut_seq_t - configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq - uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use - uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands - uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use - uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more - //! details - uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details - uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal - uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot - //! Chapter for more details - uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot - //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH - uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use - uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 - uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 - uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 - uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 - uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value - uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value - uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value - uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value - uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command - uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands - uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns - uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 - uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - - //! busy flag is 0 when flash device is busy - uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences - flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences - uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use -} flexspi_mem_config_t; - -/* */ -#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 -#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 -#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 -#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 -#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 -#define NOR_CMD_LUT_SEQ_IDX_READID 8 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 -#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 -#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 -#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 - -/* - * Serial NOR configuration block - */ -typedef struct _flexspi_nor_config -{ - flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI - uint32_t pageSize; //!< Page size of Serial NOR - uint32_t sectorSize; //!< Sector size of Serial NOR - uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command - uint8_t isUniformBlockSize; //!< Sector/Block size is the same - uint8_t reserved0[2]; //!< Reserved for future use - uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 - uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command - uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false - uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution - uint32_t blockSize; //!< Block size - uint32_t reserve2[11]; //!< Reserved for future use -} flexspi_nor_config_t; - -#define FLASH_BUSY_STATUS_POL 0 -#define FLASH_BUSY_STATUS_OFFSET 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif -#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/TEENSY41/TEENSY41.ld b/ports/mimxrt/boards/TEENSY41/TEENSY41.ld deleted file mode 100755 index 7f3cfc302..000000000 --- a/ports/mimxrt/boards/TEENSY41/TEENSY41.ld +++ /dev/null @@ -1,2 +0,0 @@ -flash_size = 8M; -reserved_size = 4K; diff --git a/ports/mimxrt/boards/TEENSY41/board.json b/ports/mimxrt/boards/TEENSY41/board.json new file mode 100644 index 000000000..1f8fe37a9 --- /dev/null +++ b/ports/mimxrt/boards/TEENSY41/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy_teensy.md" + ], + "docs": "", + "features": [ + "MicroSD", + "Ethernet", + "Breadboard Friendly" + ], + "images": [ + "teensy41_4.jpg" + ], + "mcu": "mimxrt", + "product": "Teensy 4.1", + "thumbnail": "", + "url": "https://www.pjrc.com/store/teensy41.html", + "vendor": "PJRC" +} diff --git a/ports/mimxrt/boards/TEENSY41/clock_config.h b/ports/mimxrt/boards/TEENSY41/clock_config.h new file mode 100644 index 000000000..082202484 --- /dev/null +++ b/ports/mimxrt/boards/TEENSY41/clock_config.h @@ -0,0 +1,122 @@ +/* + * Copyright 2018-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */ +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockRUN configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */ + +/* Clock outputs (values are in Hz): */ +#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL +#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL +#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL +#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL +#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL +#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL +#define BOARD_BOOTCLOCKRUN_ENET1_TX_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL +#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL +#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL +#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL +#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL +#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 9642857UL +#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL +#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL +#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL +#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL +#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 24000000UL +#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL +#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL +#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL +#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL +#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL +#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL +#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 0UL +#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL +#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL + +/*! @brief Arm PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN; +/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN; +/*! @brief Sys PLL for BOARD_BootClockRUN configuration. + */ +extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN; + +/******************************************************************************* + * API for BOARD_BootClockRUN configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockRUN(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ diff --git a/ports/mimxrt/boards/TEENSY41/flash_config.c b/ports/mimxrt/boards/TEENSY41/flash_config.c deleted file mode 100755 index f5066216d..000000000 --- a/ports/mimxrt/boards/TEENSY41/flash_config.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.c - -#include "teensy41_flexspi_nor_config.h" - -/* Component ID definition, used by tools. */ -#ifndef FSL_COMPONENT_ID -#define FSL_COMPONENT_ID "platform.drivers.xip_board" -#endif - -/******************************************************************************* - * Code - ******************************************************************************/ -#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) -#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) -__attribute__((section(".boot_hdr.conf"))) -#elif defined(__ICCARM__) -#pragma location = ".boot_hdr.conf" -#endif - -const flexspi_nor_config_t qspiflash_config = { - .memConfig = - { - .tag = FLEXSPI_CFG_BLK_TAG, - .version = FLEXSPI_CFG_BLK_VERSION, - .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad, - .csHoldTime = 3u, - .csSetupTime = 3u, - - .busyOffset = FLASH_BUSY_STATUS_OFFSET, // Status bit 0 indicates busy. - .busyBitPolarity = FLASH_BUSY_STATUS_POL, // Busy when the bit is 1. - - .deviceModeCfgEnable = 1u, - .deviceModeType = kDeviceConfigCmdType_QuadEnable, - .deviceModeSeq = { - .seqId = 4u, - .seqNum = 1u, - }, - .deviceModeArg = 0x0200, - .configCmdEnable = 1u, - .configModeType[0] = kDeviceConfigCmdType_Generic, - .configCmdSeqs[0] = { - .seqId = 2u, - .seqNum = 1u, - }, - .deviceType = kFlexSpiDeviceType_SerialNOR, - // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock - .sflashPadType = kSerialFlash_4Pads, - .serialClkFreq = kFlexSpiSerialClk_60MHz, - .sflashA1Size = 8u * 1024u * 1024u, - .lookupTable = - { - // 0 Read LUTs 0 -> 0 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 1 Read status register -> 1 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 2 Fast read quad mode - SDR - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 3 Write Enable -> 3 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 4 Read extend parameters - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 5 Erase Sector -> 5 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 6 Write Status Reg - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 7 Page Program - quad mode (-> 9) - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 8 Read ID - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 9 Page Program - single mode -> 9 - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24), - FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 10 Enter QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 11 Erase Chip - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - - // 12 Exit QPI mode - FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0), - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler - }, - }, - .pageSize = 256u, - .sectorSize = 4u * 1024u, - .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz, - .blockSize = 0x00010000, - .isUniformBlockSize = false, -}; -#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h index a72bd127b..4ca82d4b6 100644 --- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h +++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h @@ -1,14 +1,10 @@ #define MICROPY_HW_BOARD_NAME "Teensy 4.1" #define MICROPY_HW_MCU_NAME "MIMXRT1062DVJ6A" -#define BOARD_FLASH_SIZE (8 * 1024 * 1024) - // Teensy 4.1 has 1 board LED #define MICROPY_HW_LED1_PIN (pin_GPIO_B0_03) #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) -#define BOARD_FLASH_CONFIG_HEADER_H "teensy41_flexspi_nor_config.h" -#define BOARD_FLASH_OPS_HEADER_H "hal/flexspi_nor_flash.h" #define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) @@ -39,10 +35,10 @@ { IOMUXC_GPIO_B0_02_LPSPI4_SDO }, { IOMUXC_GPIO_B0_01_LPSPI4_SDI }, #define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \ - kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } + kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx } #define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \ - kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } + kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx } // Define mapping hardware I2C # to logical I2C # // SDA/SCL HW-I2C Logical I2C @@ -57,3 +53,36 @@ { 0 }, { 0 }, \ { IOMUXC_GPIO_AD_B1_07_LPI2C3_SCL }, { IOMUXC_GPIO_AD_B1_06_LPI2C3_SDA }, \ { IOMUXC_GPIO_AD_B0_12_LPI2C4_SCL }, { IOMUXC_GPIO_AD_B0_13_LPI2C4_SDA }, + +#define USDHC_DUMMY_PIN NULL, 0 +#define MICROPY_USDHC1 \ + { \ + .cmd = {GPIO_SD_B0_00_USDHC1_CMD}, \ + .clk = { GPIO_SD_B0_01_USDHC1_CLK }, \ + .cd_b = { USDHC_DUMMY_PIN }, \ + .data0 = { GPIO_SD_B0_02_USDHC1_DATA0 }, \ + .data1 = { GPIO_SD_B0_03_USDHC1_DATA1 }, \ + .data2 = { GPIO_SD_B0_04_USDHC1_DATA2 }, \ + .data3 = { GPIO_SD_B0_05_USDHC1_DATA3 }, \ + } + +// Network definitions +// Transceiver Phy Address & Type +#define ENET_PHY_ADDRESS (0) +#define ENET_PHY_OPS phydp83825_ops + +// Ethernet PIN definitions +#define ENET_RESET_PIN pin_GPIO_B0_14 +#define ENET_INT_PIN pin_GPIO_B0_15 + +#define IOMUX_TABLE_ENET \ + { IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_05_ENET_RX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_06_ENET_RX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_07_ENET_TX_DATA00, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_08_ENET_TX_DATA01, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_09_ENET_TX_EN, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_10_ENET_REF_CLK, 1, 0x71u }, \ + { IOMUXC_GPIO_B1_11_ENET_RX_ER, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_15_ENET_MDIO, 0, 0xB0E9u }, \ + { IOMUXC_GPIO_B1_14_ENET_MDC, 0, 0xB0E9u }, diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk index a15dd7812..a012444ca 100755 --- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk +++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk @@ -2,9 +2,14 @@ MCU_SERIES = MIMXRT1062 MCU_VARIANT = MIMXRT1062DVJ6A MICROPY_FLOAT_IMPL = double +MICROPY_PY_MACHINE_SDCARD = 1 +MICROPY_HW_FLASH_TYPE ?= qspi_nor +MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB +MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB -SRC_C += \ - hal/flexspi_nor_flash.c \ +MICROPY_PY_LWIP = 1 +MICROPY_PY_USSL = 1 +MICROPY_SSL_MBEDTLS = 1 deploy: $(BUILD)/firmware.hex teensy_loader_cli --mcu=imxrt1062 -v -w $< diff --git a/ports/mimxrt/boards/TEENSY41/teensy41_flexspi_nor_config.h b/ports/mimxrt/boards/TEENSY41/teensy41_flexspi_nor_config.h deleted file mode 100755 index 445a0bacc..000000000 --- a/ports/mimxrt/boards/TEENSY41/teensy41_flexspi_nor_config.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2018 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -// Based on tinyusb/hw/bsp/teensy_40/teensy40_flexspi_nor_config.h - -#ifndef __TEENSY40_FLEXSPI_NOR_CONFIG__ -#define __TEENSY40_FLEXSPI_NOR_CONFIG__ - -#include -#include -#include "fsl_common.h" - -/*! @name Driver version */ -/*@{*/ -/*! @brief XIP_BOARD driver version 2.0.0. */ -#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) -/*@}*/ - -/* FLEXSPI memory config block related defintions */ -#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian -#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 -#define FLEXSPI_CFG_BLK_SIZE (512) - -/* FLEXSPI Feature related definitions */ -#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 - -/* Lookup table related definitions */ -#define CMD_INDEX_READ 0 -#define CMD_INDEX_READSTATUS 1 -#define CMD_INDEX_WRITEENABLE 2 -#define CMD_INDEX_WRITE 4 - -#define CMD_LUT_SEQ_IDX_READ 0 -#define CMD_LUT_SEQ_IDX_READSTATUS 1 -#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define CMD_LUT_SEQ_IDX_ERASE 5 -#define CMD_LUT_SEQ_IDX_WRITE 9 - -#define CMD_SDR 0x01 -#define CMD_DDR 0x21 -#define RADDR_SDR 0x02 -#define RADDR_DDR 0x22 -#define CADDR_SDR 0x03 -#define CADDR_DDR 0x23 -#define MODE1_SDR 0x04 -#define MODE1_DDR 0x24 -#define MODE2_SDR 0x05 -#define MODE2_DDR 0x25 -#define MODE4_SDR 0x06 -#define MODE4_DDR 0x26 -#define MODE8_SDR 0x07 -#define MODE8_DDR 0x27 -#define WRITE_SDR 0x08 -#define WRITE_DDR 0x28 -#define READ_SDR 0x09 -#define READ_DDR 0x29 -#define LEARN_SDR 0x0A -#define LEARN_DDR 0x2A -#define DATSZ_SDR 0x0B -#define DATSZ_DDR 0x2B -#define DUMMY_SDR 0x0C -#define DUMMY_DDR 0x2C -#define DUMMY_RWDS_SDR 0x0D -#define DUMMY_RWDS_DDR 0x2D -#define JMP_ON_CS 0x1F -#define STOP 0 - -#define FLEXSPI_1PAD 0 -#define FLEXSPI_2PAD 1 -#define FLEXSPI_4PAD 2 -#define FLEXSPI_8PAD 3 - -#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ - (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ - FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) - -//!@brief Definitions for FlexSPI Serial Clock Frequency -typedef enum _FlexSpiSerialClockFreq -{ - kFlexSpiSerialClk_30MHz = 1, - kFlexSpiSerialClk_50MHz = 2, - kFlexSpiSerialClk_60MHz = 3, - kFlexSpiSerialClk_75MHz = 4, - kFlexSpiSerialClk_80MHz = 5, - kFlexSpiSerialClk_100MHz = 6, - kFlexSpiSerialClk_120MHz = 7, - kFlexSpiSerialClk_133MHz = 8, - kFlexSpiSerialClk_166MHz = 9, -} flexspi_serial_clk_freq_t; - -//!@brief FlexSPI clock configuration type -enum -{ - kFlexSpiClk_SDR, //!< Clock configure for SDR mode - kFlexSpiClk_DDR, //!< Clock configurat for DDR mode -}; - -//!@brief FlexSPI Read Sample Clock Source definition -typedef enum _FlashReadSampleClkSource -{ - kFlexSPIReadSampleClk_LoopbackInternally = 0, - kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, - kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, - kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, -} flexspi_read_sample_clk_t; - -//!@brief Misc feature bit definitions -enum -{ - kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable - kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable - kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable - kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable - kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable - kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable - kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. -}; - -//!@brief Flash Type Definition -enum -{ - kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR - kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND - kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH - kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND - kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs -}; - -//!@brief Flash Pad Definitions -enum -{ - kSerialFlash_1Pad = 1, - kSerialFlash_2Pads = 2, - kSerialFlash_4Pads = 4, - kSerialFlash_8Pads = 8, -}; - -//!@brief FlexSPI LUT Sequence structure -typedef struct _lut_sequence -{ - uint8_t seqNum; //!< Sequence Number, valid number: 1-16 - uint8_t seqId; //!< Sequence Index, valid number: 0-15 - uint16_t reserved; -} flexspi_lut_seq_t; - -//!@brief Flash Configuration Command Type -enum -{ - kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc - kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command - kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode - kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode - kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode - kDeviceConfigCmdType_Reset, //!< Reset device command -}; - -//!@brief FlexSPI Memory Configuration Block -typedef struct _FlexSPIConfig -{ - uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL - uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix - uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use - uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 - uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 - uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 - uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For - //! Serial NAND, need to refer to datasheet - uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable - uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, - //! Generic configuration, etc. - uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for - //! DPI/QPI/OPI switch or reset command - flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt - //! sequence number, [31:16] Reserved - uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration - uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable - uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe - flexspi_lut_seq_t - configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq - uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use - uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands - uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use - uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more - //! details - uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details - uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal - uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot - //! Chapter for more details - uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot - //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH - uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use - uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 - uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 - uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 - uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 - uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value - uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value - uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value - uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value - uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command - uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands - uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns - uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 - uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - - //! busy flag is 0 when flash device is busy - uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences - flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences - uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use -} flexspi_mem_config_t; - -/* */ -#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 -#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 -#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 -#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 -#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 -#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 -#define NOR_CMD_LUT_SEQ_IDX_READID 8 -#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 -#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 -#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 -#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 - -/* - * Serial NOR configuration block - */ -typedef struct _flexspi_nor_config -{ - flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI - uint32_t pageSize; //!< Page size of Serial NOR - uint32_t sectorSize; //!< Sector size of Serial NOR - uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command - uint8_t isUniformBlockSize; //!< Sector/Block size is the same - uint8_t reserved0[2]; //!< Reserved for future use - uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 - uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command - uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false - uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution - uint32_t blockSize; //!< Block size - uint32_t reserve2[11]; //!< Reserved for future use -} flexspi_nor_config_t; - -#define FLASH_BUSY_STATUS_POL 0 -#define FLASH_BUSY_STATUS_OFFSET 0 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif -#endif /* __EVKMIMXRT1060_FLEXSPI_NOR_CONFIG__ */ diff --git a/ports/mimxrt/boards/common.ld b/ports/mimxrt/boards/common.ld index 6f45da24d..7aee66e2e 100644 --- a/ports/mimxrt/boards/common.ld +++ b/ports/mimxrt/boards/common.ld @@ -45,12 +45,19 @@ MEMORY m_itcm (RX) : ORIGIN = itcm_start, LENGTH = itcm_size m_dtcm (RW) : ORIGIN = dtcm_start, LENGTH = dtcm_size m_ocrm (RW) : ORIGIN = ocrm_start, LENGTH = ocrm_size + + #ifdef MICROPY_HW_SDRAM_AVAIL + m_sdram (RX) : ORIGIN = sdram_start, LENGTH = sdram_size + #endif } /* Define output sections */ SECTIONS { __flash_start = flash_start; + #ifdef MICROPY_HW_SDRAM_AVAIL + __sdram_start = sdram_start; + #endif __vfs_start = ORIGIN(m_vfs); __vfs_end = __vfs_start + LENGTH(m_vfs); @@ -89,7 +96,7 @@ SECTIONS .text : { . = ALIGN(4); - *(EXCLUDE_FILE(*fsl_flexspi.o) .text*) /* .text* sections (code) */ + *(EXCLUDE_FILE(*fsl_flexspi.o *gc*.o *vm.o *parse.o *runtime*.o *mpirq.o *map.o) .text*) /* .text* sections (code) */ *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ *(.glue_7) /* glue arm to thumb code */ @@ -193,8 +200,9 @@ SECTIONS { . = ALIGN(4); __ram_function_start__ = .; - *fsl_flexspi.o(.text*) *(.ram_functions*) + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) . = ALIGN(4); __ram_function_end__ = .; } > m_itcm diff --git a/ports/mimxrt/boards/deploy_mimxrt.md b/ports/mimxrt/boards/deploy_mimxrt.md new file mode 100644 index 000000000..35752a836 --- /dev/null +++ b/ports/mimxrt/boards/deploy_mimxrt.md @@ -0,0 +1,11 @@ +Firmware can be loaded to the MIMXRT development boards in various ways. The most convenient +one is using the built-in support MCU. When a PC is connected to the debug USB port, a drive +icon will appear. Firmware can be uploaded to the board by copying it to this drive. The copy +and flashing will take a few moments. At the end of the upload, the drive icon will disappear +and reappear again. Then the reset button has to be pushed, which starts the MicroPython firmware. + +Depending on the power jumper settings, both the debug USB and OTG USB port have to be powered +during firmware upload. + +You may as well load the firmware using the JLink port or openSDA interface with the appropriate tools. +For more options, consult the user guide of the board. diff --git a/ports/mimxrt/boards/deploy_teensy.md b/ports/mimxrt/boards/deploy_teensy.md new file mode 100644 index 000000000..f48154490 --- /dev/null +++ b/ports/mimxrt/boards/deploy_teensy.md @@ -0,0 +1,14 @@ +For deploying the firmware use the Teensy Loader tool provided by PJRC on their web site. +PJRC provides both a graphical and command line version for Windows, OS X and Linux. +With the command line version, run the command: + +```bash +teensy_loader_cli --mcu=imxrt1062 -v -w TEENSY40-.hex +``` +or for Teensy 4.1: + +```bash +teensy_loader_cli --mcu=imxrt1062 -v -w TEENSY41-.hex +``` + +When loading the firmware the PJRC boot loader will erase the content of the board file system. diff --git a/ports/mimxrt/boards/make-flexram-config.py b/ports/mimxrt/boards/make-flexram-config.py new file mode 100644 index 000000000..0a667ff5b --- /dev/null +++ b/ports/mimxrt/boards/make-flexram-config.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 +# +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2021 Philipp Ebensberger +# +# 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. + +"""Evaluate FlexRAM configuration and generate startup code.""" + +import re +import argparse + +# Regex for linker script configuration +ocram_regex = r"^\s*ocrm_size\s*=\s*(?P.*);" +dtcm_regex = r"^\s*dtcm_size\s*=\s*(?P.*);" +itcm_regex = r"^\s*itcm_size\s*=\s*(?P.*);" + +# Regex for GPR register base define in NXL hal +gpr_base_regex = r"^.*IOMUXC_GPR_BASE\s*\((?P\w*)u\)" + +# Regex for FlexRAM parameters in NXP HAL +fsl_ram_bank_size_regex = r"^.*FSL_FEATURE_FLEXRAM_INTERNAL_RAM_BANK_SIZE\s*\((?P\w*)\)" +fsl_bank_nbr_regex = ( + r"^.*FSL_FEATURE_FLEXRAM_INTERNAL_RAM_TOTAL_BANK_NUMBERS\s*\((?P\w*)\)" +) + + +""" +According to AN12077: + The minimum configuration of OCRAM is 64 KB. This is required + due to ROM code requires at least 64 KB of RAM for its execution. + + 2.1.1.1. Static configuration - Page 4 +""" +ocram_min_size = 0x00010000 # 64 KB + +# Value parser +def mimxrt_default_parser(defines_file, features_file, ld_script): + with open(ld_script, "r") as input_file: + input_str = input_file.read() + # + ocram_match = re.search(ocram_regex, input_str, re.MULTILINE) + dtcm_match = re.search(dtcm_regex, input_str, re.MULTILINE) + itcm_match = re.search(itcm_regex, input_str, re.MULTILINE) + + with open(defines_file, "r") as input_file: + input_str = input_file.read() + mcu_define_file_match = re.search(gpr_base_regex, input_str, re.MULTILINE) + + with open(features_file, "r") as input_file: + input_str = input_file.read() + fsl_ram_bank_size_match = re.search(fsl_ram_bank_size_regex, input_str, re.MULTILINE) + fsl_bank_nbr_match = re.search(fsl_bank_nbr_regex, input_str, re.MULTILINE) + # + extract = { + "ocram_size": int(ocram_match.group("size"), 16), + "dtcm_size": int(dtcm_match.group("size"), 16), + "itcm_size": int(itcm_match.group("size"), 16), + "gpr_base_addr": int(mcu_define_file_match.group("base_addr"), 16), + "fsl_ram_bank_size": int(fsl_ram_bank_size_match.group("size")), + "fsl_bank_nbr": int(fsl_bank_nbr_match.group("number")), + } + # Evaluate configuration + if extract["ocram_size"] < ocram_min_size: + raise ValueError("OCRAM size must be at least {:08X}!".format(ocram_min_size)) + + if (extract["ocram_size"] % extract["fsl_ram_bank_size"]) != 0: + raise ValueError("Configuration invalid!") + + # Check if DTCM and ITCM size is either multiple of 32k or 4k,8k or 16k + if extract["dtcm_size"] != 0x0: + if extract["dtcm_size"] % extract["fsl_ram_bank_size"] != 0: + if extract["dtcm_size"] not in (0x00000000, 0x00001000, 0x00002000, 0x00004000): + raise ValueError("Configuration invalid!") + + if extract["itcm_size"] != 0x0: + if extract["itcm_size"] % extract["fsl_ram_bank_size"] != 0: + if extract["itcm_size"] not in (0x00000000, 0x00001000, 0x00002000, 0x00004000): + raise ValueError("Configuration invalid!") + # + return extract + + +# Code generators +def mimxrt_default_gen_code(extract_dict): + flexram_bank_cfg = "0b" + avail_flexram = extract_dict["fsl_ram_bank_size"] * extract_dict["fsl_bank_nbr"] + + if ( + extract_dict["ocram_size"] + extract_dict["dtcm_size"] + extract_dict["itcm_size"] + ) > avail_flexram: + raise ValueError("Configuration exceeds available FlexRAM!") + + bit_patterns = ( + (extract_dict["ocram_size"], "01"), + (extract_dict["dtcm_size"], "10"), + (extract_dict["itcm_size"], "11"), + ) + + for size, pattern in bit_patterns: + for _ in range(0, size, extract_dict["fsl_ram_bank_size"]): + flexram_bank_cfg += pattern + + # Generate GPR Register config + print(".equ __iomux_gpr14_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x38)) + print(".equ __iomux_gpr16_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x40)) + print(".equ __iomux_gpr17_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x44)) + print( + ".equ __iomux_gpr17_value, 0x{:08X} /* {}k OCRAM, {}k DTCM, {}k ITCM */".format( + int(flexram_bank_cfg, 2), + extract_dict["ocram_size"] // 1024, + extract_dict["dtcm_size"] // 1024, + extract_dict["itcm_size"] // 1024, + ) + ) + + +def mimxrt_106x_gen_code(extract_dict): + flexram_bank_cfg = "0b" + avail_flexram = extract_dict["fsl_ram_bank_size"] * extract_dict["fsl_bank_nbr"] + flexram_configurable_ocram = ( + extract_dict["ocram_size"] % 524288 + ) # 512kB OCRAM are not part of FlexRAM configurable memory + + if ( + flexram_configurable_ocram + extract_dict["dtcm_size"] + extract_dict["itcm_size"] + ) > avail_flexram: + raise ValueError("Configuration exceeds available FlexRAM!") + + for size, pattern in ( + (flexram_configurable_ocram, "01"), + (extract_dict["dtcm_size"], "10"), + (extract_dict["itcm_size"], "11"), + ): + for _ in range(0, size, extract_dict["fsl_ram_bank_size"]): + flexram_bank_cfg += pattern + + # Generate GPR Register config + print(".equ __iomux_gpr14_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x38)) + print(".equ __iomux_gpr16_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x40)) + print(".equ __iomux_gpr17_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x44)) + print( + ".equ __iomux_gpr17_value, 0x{:08X} /* {}k OCRAM (512k OCRAM, {}k from FlexRAM), {}k DTCM, {}k ITCM */".format( + int(flexram_bank_cfg, 2), + extract_dict["ocram_size"] // 1024, + flexram_configurable_ocram // 1024, + extract_dict["dtcm_size"] // 1024, + extract_dict["itcm_size"] // 1024, + ) + ) + + +def main(defines_file, features_file, ld_script, controller): + dispatcher = { + "MIMXRT1011": (mimxrt_default_parser, mimxrt_default_gen_code), + "MIMXRT1021": (mimxrt_default_parser, mimxrt_default_gen_code), + "MIMXRT1052": (mimxrt_default_parser, mimxrt_default_gen_code), + "MIMXRT1062": (mimxrt_default_parser, mimxrt_106x_gen_code), + "MIMXRT1064": (mimxrt_default_parser, mimxrt_106x_gen_code), + } + + extractor, code_generator = dispatcher[controller] + + extract_dict = extractor(defines_file, features_file, ld_script) + code_generator(extract_dict) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + prog="make-flexram-ld.py", + usage="%(prog)s [options] [command]", + description="Evaluate FlexRAM configuration and generate startup code.", + ) + parser.add_argument( + "-d", + "--defines_file", + dest="defines_file", + help="Path to MCU defines file", + default="../../../lib/nxp_driver/sdk/devices/MIMXRT1021/MIMXRT1021.h", + ) + parser.add_argument( + "-f", + "--features_file", + dest="features_file", + help="Path to MCU features file", + default="../../../lib/nxp_driver/sdk/devices/MIMXRT1021/MIMXRT1021_features.h", + ) + parser.add_argument( + "-l", + "--ld_file", + dest="linker_file", + help="Path to the aggregated linker-script", + default="MIMXRT1021.ld", + ) + parser.add_argument( + "-c", "--controller", dest="controller", help="Controller name", default="MIMXRT1021" + ) + # + args = parser.parse_args() + main(args.defines_file, args.features_file, args.linker_file, args.controller) diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py index e9e32a504..441676add 100644 --- a/ports/mimxrt/boards/make-pins.py +++ b/ports/mimxrt/boards/make-pins.py @@ -8,11 +8,22 @@ import sys import csv import re -SUPPORTED_AFS = {"GPIO"} +SUPPORTED_AFS = {"GPIO", "USDHC", "FLEXPWM", "TMR"} MAX_AF = 10 # AF0 .. AF9 ADC_COL = 11 +regexes = [ + r"IOMUXC_(?PGPIO_SD_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_AD_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_EMC_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_AD_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", + r"IOMUXC_(?PGPIO_SD_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", +] + + def parse_pad(pad_str): """Parses a string and returns a (port, gpio_bit) tuple.""" if len(pad_str) < 4: @@ -127,16 +138,18 @@ class AdcFunction(object): class AlternateFunction(object): """Holds the information associated with a pins alternate function.""" - def __init__(self, idx, af_str): + def __init__(self, idx, input_reg, input_daisy, af_str): self.idx = idx self.af_str = af_str + self.input_reg = input_reg + self.input_daisy = input_daisy self.instance = self.af_str.split("_")[0] def print(self): """Prints the C representation of this AF.""" print( - " PIN_AF({0}, PIN_AF_MODE_ALT{1}, {2}, {3}),".format( - self.af_str, self.idx, self.instance, "0x10B0U" + " PIN_AF({0}, PIN_AF_MODE_ALT{1}, {2}, {3}, {4}, {5}),".format( + self.af_str, self.idx, self.input_daisy, self.instance, self.input_reg, "0x10B0U" ) ) @@ -167,12 +180,36 @@ class Pins(object): with open(filename, "r") as csvfile: rows = csv.reader(csvfile) for row in rows: + if len(row) == 0 or row[0].startswith("#"): + # Skip empty lines, and lines starting with "#" + continue + if len(row) != 2: + raise ValueError("Expecting two entries in a row") + pin = self.find_pin_by_name(row[1]) if pin and row[0]: # Only add board pins that have a name self.board_pins.append(NamedPin(row[0], pin.pad, pin.idx)) - def parse_af_file(self, filename, pad_col, af_start_col): + def parse_af_file(self, filename, iomux_filename, pad_col, af_start_col): af_end_col = af_start_col + MAX_AF + + iomux_pin_config = dict() + + with open(iomux_filename, "r") as ipt: + input_str = ipt.read() + for regex in regexes: + matches = re.finditer(regex, input_str, re.MULTILINE) + + for match in matches: + if match.group("pin") not in iomux_pin_config: + iomux_pin_config[match.group("pin")] = { + int((match.groupdict()["muxMode"].strip("U")), 16): match.groupdict() + } + else: + iomux_pin_config[match.group("pin")][ + int((match.groupdict()["muxMode"].strip("U")), 16) + ] = match.groupdict() + with open(filename, "r") as csvfile: rows = csv.reader(csvfile) header = next(rows) @@ -187,7 +224,16 @@ class Pins(object): af_idx = 0 for af_idx, af in enumerate(row[af_start_col:af_end_col]): if af and af_supported(af): - pin.add_af(AlternateFunction(af_idx, af)) + pin.add_af( + AlternateFunction( + af_idx, + iomux_pin_config[pin.name][af_idx]["inputRegister"].strip("U"), + int( + iomux_pin_config[pin.name][af_idx]["inputDaisy"].strip("U"), 16 + ), + af, + ) + ) pin.parse_adc(row[ADC_COL]) @@ -235,6 +281,37 @@ class Pins(object): hdr_file.write("extern const mp_obj_dict_t machine_pin_cpu_pins_locals_dict;\n") hdr_file.write("extern const mp_obj_dict_t machine_pin_board_pins_locals_dict;\n") + hdr_file.write("\n// Defines\n") + module_instance_factory(self.cpu_pins, hdr_file, "USDHC") + module_instance_factory(self.cpu_pins, hdr_file, "FLEXPWM") + module_instance_factory(self.cpu_pins, hdr_file, "TMR") + + +def module_instance_factory(pins, output_file, name): + module_pin = filter(lambda p: any([af for af in p.alt_fn if name in af.af_str]), pins) + + module_instances = dict() + for pin in module_pin: + for idx, alt_fn in enumerate(pin.alt_fn): + if name in alt_fn.instance: + format_string = "#define {0}_{1} &pin_{0}, {2}" + if alt_fn.instance not in module_instances: + module_instances[alt_fn.instance] = [ + format_string.format(pin.name, alt_fn.af_str, idx) + ] + else: + module_instances[alt_fn.instance].append( + format_string.format(pin.name, alt_fn.af_str, idx) + ) + + for k, v in module_instances.items(): + output_file.write(f"// {k}\n") + output_file.write(f"#define {k}_AVAIL (1)\n") + if name == "FLEXPWM": + output_file.write(f"#define {k} {k[-4:]}\n") + for i in v: + output_file.write(i + "\n") + def main(): parser = argparse.ArgumentParser( @@ -249,6 +326,13 @@ def main(): help="Specifies the alternate function file for the chip", default="mimxrt1021_af.csv", ) + parser.add_argument( + "-i", + "--iomux", + dest="iomux_filename", + help="Specifies the fsl_iomuxc.h file for the chip", + default="fsl_iomuxc.h", + ) parser.add_argument( "-b", "--board", @@ -279,7 +363,7 @@ def main(): if args.af_filename: print("// --af {:s}".format(args.af_filename)) - pins.parse_af_file(args.af_filename, 0, 1) + pins.parse_af_file(args.af_filename, args.iomux_filename, 0, 1) if args.board_filename: print("// --board {:s}".format(args.board_filename)) diff --git a/ports/mimxrt/boards/manifest.py b/ports/mimxrt/boards/manifest.py index 9df589f12..ccbd33cae 100644 --- a/ports/mimxrt/boards/manifest.py +++ b/ports/mimxrt/boards/manifest.py @@ -1,3 +1,4 @@ freeze("$(PORT_DIR)/modules") freeze("$(MPY_DIR)/drivers/onewire") +freeze("$(MPY_DIR)/drivers/dht", "dht.py") include("$(MPY_DIR)/extmod/uasyncio/manifest.py") diff --git a/ports/mimxrt/boards/mimxrt_prefix.c b/ports/mimxrt/boards/mimxrt_prefix.c index 96ba6a0d5..938efc810 100644 --- a/ports/mimxrt/boards/mimxrt_prefix.c +++ b/ports/mimxrt/boards/mimxrt_prefix.c @@ -4,12 +4,14 @@ #include "py/mphal.h" #include "pin.h" -#define PIN_AF(_name, _af_mode, _instance, _pad_config) \ +#define PIN_AF(_name, _af_mode, _input_daisy, _instance, _input_register, _pad_config) \ { \ .base = { &machine_pin_af_type }, \ .name = MP_QSTR_##_name, \ .af_mode = (uint32_t)(_af_mode), \ + .input_daisy = (uint8_t)(_input_daisy), \ .instance = (void *)(_instance), \ + .input_register = (uint32_t)(_input_register), \ .pad_config = (uint32_t)(_pad_config), \ } \ @@ -32,3 +34,4 @@ .af_list = (_af_list), \ .adc_list = (_adc_list), \ } \ + diff --git a/ports/mimxrt/dma_channel.c b/ports/mimxrt/dma_channel.c index 3dd043a66..c6cae9da9 100644 --- a/ports/mimxrt/dma_channel.c +++ b/ports/mimxrt/dma_channel.c @@ -27,10 +27,17 @@ #include "dma_channel.h" // List of channel flags: true: channel used, false: channel available -static bool channel_list[32] = { true, true, true, true, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false }; +static bool channel_list[FSL_FEATURE_DMAMUX_MODULE_CHANNEL] = { + true, true, true, true, false, false, false, false, + false, false, false, false, false, false, false, false, + + #if FSL_FEATURE_DMAMUX_MODULE_CHANNEL > 16 + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false + + #endif +}; // allocate_channel(): retrieve an available channel. Return the number or -1 int allocate_dma_channel(void) { diff --git a/ports/mimxrt/eth.c b/ports/mimxrt/eth.c new file mode 100644 index 000000000..1a8210cb1 --- /dev/null +++ b/ports/mimxrt/eth.c @@ -0,0 +1,440 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * Copyright (c) 2021 Robert Hammelrath + * + * 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 "ticks.h" + +#if defined(MICROPY_HW_ETH_MDC) + +#include "pin.h" +#include "shared/netutils/netutils.h" +#include "extmod/modnetwork.h" + +#include "fsl_iomuxc.h" +#include "fsl_enet.h" +#include "fsl_phy.h" +#include "hal/phy/mdio/enet/fsl_enet_mdio.h" +#include "hal/phy/device/phyksz8081/fsl_phyksz8081.h" +#include "hal/phy/device/phydp83825/fsl_phydp83825.h" +#include "hal/phy/device/phylan8720/fsl_phylan8720.h" + +#include "eth.h" +#include "lwip/etharp.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" +#include "netif/ethernet.h" + +#include "ticks.h" + +// Configuration values +enet_config_t enet_config; +phy_config_t phyConfig = {0}; + +// Prepare the buffer configuration. + +#define ENET_RXBD_NUM (5) +#define ENET_TXBD_NUM (5) + +AT_NONCACHEABLE_SECTION_ALIGN(enet_rx_bd_struct_t g_rxBuffDescrip[ENET_RXBD_NUM], ENET_BUFF_ALIGNMENT); +AT_NONCACHEABLE_SECTION_ALIGN(enet_tx_bd_struct_t g_txBuffDescrip[ENET_TXBD_NUM], ENET_BUFF_ALIGNMENT); +SDK_ALIGN(uint8_t g_rxDataBuff[ENET_RXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)], + ENET_BUFF_ALIGNMENT); +SDK_ALIGN(uint8_t g_txDataBuff[ENET_TXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)], + ENET_BUFF_ALIGNMENT); + +// ENET Handles & Buffers +enet_handle_t g_handle; + +static mdio_handle_t mdioHandle = {.ops = &enet_ops}; +static phy_handle_t phyHandle = {.phyAddr = ENET_PHY_ADDRESS, .mdioHandle = &mdioHandle, .ops = &ENET_PHY_OPS}; + +enet_buffer_config_t buffConfig[] = {{ + ENET_RXBD_NUM, + ENET_TXBD_NUM, + SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT), + SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT), + &g_rxBuffDescrip[0], + &g_txBuffDescrip[0], + &g_rxDataBuff[0][0], + &g_txDataBuff[0][0], + }}; + +static uint8_t hw_addr[6]; // The MAC address field +eth_t eth_instance; + +#define PHY_INIT_TIMEOUT_MS (10000) +#define PHY_AUTONEGO_TIMEOUT_US (5000000) + +typedef struct _eth_t { + uint32_t trace_flags; + struct netif netif; + struct dhcp dhcp_struct; +} eth_t; + +typedef struct _iomux_table_t { + uint32_t muxRegister; + uint32_t muxMode; + uint32_t inputRegister; + uint32_t inputDaisy; + uint32_t configRegister; + uint32_t inputOnfield; + uint32_t configValue; +} iomux_table_t; + +static const iomux_table_t iomux_table_enet[] = { + IOMUX_TABLE_ENET +}; + +#define IOTE (iomux_table_enet[i]) + +#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 void eth_process_frame(eth_t *self, uint8_t *buf, size_t length) { + + struct netif *netif = &self->netif; + if (netif->flags & NETIF_FLAG_LINK_UP) { + struct pbuf *p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL); + if (p != NULL) { + // Need to create a local copy first, since ENET_ReadFrame does not + // provide a pointer to the buffer. + pbuf_take(p, buf, length); + if (netif->input(p, netif) != ERR_OK) { + pbuf_free(p); + } + } + } +} + +void eth_irq_handler(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *userData) { + eth_t *self = (eth_t *)userData; + uint8_t g_rx_frame[ENET_FRAME_MAX_FRAMELEN + 14]; + uint32_t length = 0; + status_t status; + + if (event == kENET_RxEvent) { + do { + status = ENET_GetRxFrameSize(handle, &length); + if (status == kStatus_Success) { + // Get the data + ENET_ReadFrame(base, handle, g_rx_frame, length); + eth_process_frame(self, g_rx_frame, length); + } else if (status == kStatus_ENET_RxFrameError) { + ENET_ReadFrame(base, handle, NULL, 0); + } + } while (status != kStatus_ENET_RxFrameEmpty); + } else { + ENET_ClearInterruptStatus(base, kENET_TxFrameInterrupt); + } +} + +// eth_init: Set up GPIO and the transceiver +void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock) { + + self->netif.num = mac_idx; // Set the interface number + + CLOCK_EnableClock(kCLOCK_Iomuxc); + + gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode}; + (void)gpio_config; + + #ifdef ENET_RESET_PIN + // Configure the Reset Pin + const machine_pin_obj_t *reset_pin = &ENET_RESET_PIN; + const machine_pin_af_obj_t *af_obj = pin_find_af(reset_pin, PIN_AF_MODE_ALT5); + + IOMUXC_SetPinMux(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister, 0U); + IOMUXC_SetPinConfig(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister, 0xB0A9U); + GPIO_PinInit(reset_pin->gpio, reset_pin->pin, &gpio_config); + #endif + + #ifdef ENET_INT_PIN + // Configure the Int Pin + const machine_pin_obj_t *int_pin = &ENET_INT_PIN; + af_obj = pin_find_af(int_pin, PIN_AF_MODE_ALT5); + + IOMUXC_SetPinMux(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister, 0U); + IOMUXC_SetPinConfig(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister, 0xB0A9U); + GPIO_PinInit(int_pin->gpio, int_pin->pin, &gpio_config); + #endif + + // Configure the Transceiver Pins, Settings except for CLK: + // Slew Rate Field: Fast Slew Rate, Drive Strength, R0/5, Speed max(200MHz) + // Open Drain Disabled, Pull Enabled, Pull 100K Ohm Pull Up + // Hysteresis Disabled + + for (int i = 0; i < ARRAY_SIZE(iomux_table_enet); i++) { + IOMUXC_SetPinMux(IOTE.muxRegister, IOTE.muxMode, IOTE.inputRegister, IOTE.inputDaisy, IOTE.configRegister, IOTE.inputOnfield); + IOMUXC_SetPinConfig(IOTE.muxRegister, IOTE.muxMode, IOTE.inputRegister, IOTE.inputDaisy, IOTE.configRegister, IOTE.configValue); + } + + const clock_enet_pll_config_t config = { + .enableClkOutput = phy_clock, .enableClkOutput25M = false, .loopDivider = 1 + }; + CLOCK_InitEnetPll(&config); + + IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false); // Do not use the 25 MHz MII clock + IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, phy_clock); // Set the clock pad direction + + // Reset transceiver + // pull up the ENET_INT before RESET. + #ifdef ENET_INT_PIN + GPIO_WritePinOutput(int_pin->gpio, int_pin->pin, 1); + #endif + + #ifdef ENET_RESET_PIN + GPIO_WritePinOutput(reset_pin->gpio, reset_pin->pin, 0); + mp_hal_delay_us(1000); + GPIO_WritePinOutput(reset_pin->gpio, reset_pin->pin, 1); + mp_hal_delay_us(1000); + #endif + + mp_hal_get_mac(0, hw_addr); + + phyHandle.ops = phy_ops; + phyConfig.phyAddr = phy_addr; + phyConfig.autoNeg = true; + mdioHandle.resource.base = ENET; + mdioHandle.resource.csrClock_Hz = CLOCK_GetFreq(kCLOCK_IpgClk); + + // Init the PHY interface & negotiate the speed + bool link = false; + bool autonego = false; + phy_speed_t speed = kENET_MiiSpeed100M; + phy_duplex_t duplex = kENET_MiiFullDuplex; + + + status_t status = PHY_Init(&phyHandle, &phyConfig); + if (status == kStatus_Success) { + if (phyConfig.autoNeg) { + uint64_t t = ticks_us64() + PHY_AUTONEGO_TIMEOUT_US; + // Wait for auto-negotiation success and link up + do { + PHY_GetAutoNegotiationStatus(&phyHandle, &autonego); + PHY_GetLinkStatus(&phyHandle, &link); + if (autonego && link) { + break; + } + } while (ticks_us64() < t); + if (!autonego) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Auto-negotiation failed.")); + } + PHY_GetLinkSpeedDuplex(&phyHandle, &speed, &duplex); + } else { + PHY_SetLinkSpeedDuplex(&phyHandle, speed, duplex); + } + } else { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Init failed.")); + } + + ENET_GetDefaultConfig(&enet_config); + enet_config.miiSpeed = (enet_mii_speed_t)speed; + enet_config.miiDuplex = (enet_mii_duplex_t)duplex; + enet_config.miiMode = kENET_RmiiMode; + // Enable checksum generation by the ENET controller + enet_config.txAccelerConfig = kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled; + // Set interrupt + enet_config.interrupt |= ENET_TX_INTERRUPT | ENET_RX_INTERRUPT; + + ENET_Init(ENET, &g_handle, &enet_config, &buffConfig[0], hw_addr, CLOCK_GetFreq(kCLOCK_IpgClk)); + ENET_SetCallback(&g_handle, eth_irq_handler, (void *)self); + ENET_EnableInterrupts(ENET, ENET_RX_INTERRUPT); + ENET_ClearInterruptStatus(ENET, ENET_TX_INTERRUPT | ENET_RX_INTERRUPT | ENET_ERR_INTERRUPT); + ENET_ActiveRead(ENET); +} + +// Initialize the phy interface +STATIC int eth_mac_init(eth_t *self) { + return 0; +} + +// Deinit the interface +STATIC void eth_mac_deinit(eth_t *self) { +} + +void eth_set_trace(eth_t *self, uint32_t value) { + self->trace_flags = value; +} + +/*******************************************************************************/ +// ETH-LwIP bindings + +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 + status_t status; + + LINK_STATS_INC(link.xmit); + eth_trace(netif->state, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE); + + if (p->next == NULL) { + status = ENET_SendFrame(ENET, &g_handle, p->payload, p->len); + } else { + // frame consists of several parts. Copy them together and send them + size_t length = 0; + uint8_t tx_frame[ENET_FRAME_MAX_FRAMELEN + 14]; + + while (p) { + memcpy(&tx_frame[length], p->payload, p->len); + length += p->len; + p = p->next; + } + status = ENET_SendFrame(ENET, &g_handle, tx_frame, length); + } + return status == kStatus_Success ? ERR_OK : ERR_BUF; +} + +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], 192, 168, 0, 2); + IP4_ADDR(&ipconfig[1], 255, 255, 255, 0); + IP4_ADDR(&ipconfig[2], 192, 168, 0, 1); + IP4_ADDR(&ipconfig[3], 8, 8, 8, 8); + + self->netif.hwaddr_len = 6; + memcpy(self->netif.hwaddr, hw_addr, 6); + + 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 +} + +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 { + bool link; + PHY_GetLinkStatus(&phyHandle, &link); + if (link) { + return 1; // link up + } else { + return 0; // link down + } + } +} + +int eth_start(eth_t *self) { + eth_lwip_deinit(self); + + // Make sure Eth is Not in low power mode. + eth_low_power_mode(self, false); + + 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; +} + +void eth_low_power_mode(eth_t *self, bool enable) { + ENET_EnableSleepMode(ENET, enable); +} +#endif // defined(MICROPY_HW_ETH_MDC) diff --git a/ports/mimxrt/eth.h b/ports/mimxrt/eth.h new file mode 100644 index 000000000..b225d0049 --- /dev/null +++ b/ports/mimxrt/eth.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 + * Copyright (c) 2021 Robert Hammelrath + * + * 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_MIMXRT_ETH_H +#define MICROPY_INCLUDED_MIMXRT_ETH_H + +typedef struct _eth_t eth_t; +extern eth_t eth_instance; + +void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock); +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); +void eth_low_power_mode(eth_t *self, bool enable); + +enum { + PHY_KSZ8081 = 0, + PHY_DP83825, + PHY_DP83848, + PHY_LAN8720, +}; + +enum { + PHY_TX_CLK_IN = false, + PHY_TX_CLK_OUT = true, +}; + +#endif // MICROPY_INCLUDED_MIMXRT_ETH_H diff --git a/ports/mimxrt/fatfs_port.c b/ports/mimxrt/fatfs_port.c new file mode 100644 index 000000000..7b7008667 --- /dev/null +++ b/ports/mimxrt/fatfs_port.c @@ -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 + * Copyright (c) 2021 Robert Hammelrath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "lib/oofatfs/ff.h" +#include "fsl_snvs_lp.h" + + +MP_WEAK DWORD get_fattime(void) { + snvs_lp_srtc_datetime_t srtcDate; + + SNVS_LP_SRTC_GetDatetime(SNVS, &srtcDate); + + return ((srtcDate.year - 1980) << 25) | (srtcDate.month << 21) | (srtcDate.day << 16) | + (srtcDate.hour << 11) | ((srtcDate.minute << 5) | (srtcDate.second / 2)); +} diff --git a/ports/mimxrt/hal/board.h b/ports/mimxrt/hal/board.h new file mode 100644 index 000000000..ce5e04797 --- /dev/null +++ b/ports/mimxrt/hal/board.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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_MIMXRT_BOARD_H +#define MICROPY_INCLUDED_MIMXRT_BOARD_H + +#include "clock_config.h" +#include "fsl_common.h" + +#endif /* MICROPY_INCLUDED_MIMXRT_BOARD_H */ diff --git a/ports/mimxrt/hal/flexspi_flash_config.h b/ports/mimxrt/hal/flexspi_flash_config.h new file mode 100644 index 000000000..3c21eb609 --- /dev/null +++ b/ports/mimxrt/hal/flexspi_flash_config.h @@ -0,0 +1,263 @@ +/* + * Copyright 2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __FLEXSPI_FLASH_CONFIG__ +#define __FLEXSPI_FLASH_CONFIG__ + +#include +#include +#include "fsl_flexspi.h" + +/*! @name Driver version */ +/*@{*/ +/*! @brief XIP_BOARD driver version 2.0.0. */ +#define FSL_XIP_BOARD_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) +/*@}*/ + +/* FLEXSPI memory config block related defintions */ +#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian +#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 +#define FLEXSPI_CFG_BLK_SIZE (512) + +/* FLEXSPI Feature related definitions */ +#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 + +/* Lookup table related defintions */ +#define CMD_INDEX_READ 0 +#define CMD_INDEX_READSTATUS 1 +#define CMD_INDEX_WRITEENABLE 2 +#define CMD_INDEX_WRITE 4 + +#define CMD_LUT_SEQ_IDX_READ 0 +#define CMD_LUT_SEQ_IDX_READSTATUS 1 +#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 +#define CMD_LUT_SEQ_IDX_WRITE 9 + +#define CMD_SDR 0x01 +#define CMD_DDR 0x21 +#define RADDR_SDR 0x02 +#define RADDR_DDR 0x22 +#define CADDR_SDR 0x03 +#define CADDR_DDR 0x23 +#define MODE1_SDR 0x04 +#define MODE1_DDR 0x24 +#define MODE2_SDR 0x05 +#define MODE2_DDR 0x25 +#define MODE4_SDR 0x06 +#define MODE4_DDR 0x26 +#define MODE8_SDR 0x07 +#define MODE8_DDR 0x27 +#define WRITE_SDR 0x08 +#define WRITE_DDR 0x28 +#define READ_SDR 0x09 +#define READ_DDR 0x29 +#define LEARN_SDR 0x0A +#define LEARN_DDR 0x2A +#define DATSZ_SDR 0x0B +#define DATSZ_DDR 0x2B +#define DUMMY_SDR 0x0C +#define DUMMY_DDR 0x2C +#define DUMMY_RWDS_SDR 0x0D +#define DUMMY_RWDS_DDR 0x2D +#define JMP_ON_CS 0x1F +#define STOP 0 + +#define FLEXSPI_1PAD 0 +#define FLEXSPI_2PAD 1 +#define FLEXSPI_4PAD 2 +#define FLEXSPI_8PAD 3 + +#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ + FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) + +// !@brief Definitions for FlexSPI Serial Clock Frequency +typedef enum _FlexSpiSerialClockFreq +{ + kFlexSpiSerialClk_30MHz = 1, + kFlexSpiSerialClk_50MHz = 2, + kFlexSpiSerialClk_60MHz = 3, + kFlexSpiSerialClk_75MHz = 4, + kFlexSpiSerialClk_80MHz = 5, + kFlexSpiSerialClk_100MHz = 6, + kFlexSpiSerialClk_133MHz = 7, + kFlexSpiSerialClk_166MHz = 8, +} flexspi_serial_clk_freq_t; + +// !@brief FlexSPI clock configuration type +enum +{ + kFlexSpiClk_SDR, // !< Clock configure for SDR mode + kFlexSpiClk_DDR, // !< Clock configurat for DDR mode +}; + +// !@brief FlexSPI Read Sample Clock Source definition +typedef enum _FlashReadSampleClkSource +{ + kFlexSPIReadSampleClk_LoopbackInternally = 0, + kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, + kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, + kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, +} flexspi_read_sample_clk_t; + +// !@brief Misc feature bit definitions +enum +{ + kFlexSpiMiscOffset_DiffClkEnable = 0, // !< Bit for Differential clock enable + kFlexSpiMiscOffset_Ck2Enable = 1, // !< Bit for CK2 enable + kFlexSpiMiscOffset_ParallelEnable = 2, // !< Bit for Parallel mode enable + kFlexSpiMiscOffset_WordAddressableEnable = 3, // !< Bit for Word Addressable enable + kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, // !< Bit for Safe Configuration Frequency enable + kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, // !< Bit for Pad setting override enable + kFlexSpiMiscOffset_DdrModeEnable = 6, // !< Bit for DDR clock confiuration indication. +}; + +// !@brief Flash Type Definition +enum +{ + kFlexSpiDeviceType_SerialNOR = 1, // !< Flash devices are Serial NOR + kFlexSpiDeviceType_SerialNAND = 2, // !< Flash devices are Serial NAND + kFlexSpiDeviceType_SerialRAM = 3, // !< Flash devices are Serial RAM/HyperFLASH + kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND + kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs +}; + +// !@brief Flash Pad Definitions +enum +{ + kSerialFlash_1Pad = 1, + kSerialFlash_2Pads = 2, + kSerialFlash_4Pads = 4, + kSerialFlash_8Pads = 8, +}; + +// !@brief FlexSPI LUT Sequence structure +typedef struct _lut_sequence +{ + uint8_t seqNum; // !< Sequence Number, valid number: 1-16 + uint8_t seqId; // !< Sequence Index, valid number: 0-15 + uint16_t reserved; +} flexspi_lut_seq_t; + +// !@brief Flash Configuration Command Type +enum +{ + kDeviceConfigCmdType_Generic, // !< Generic command, for example: configure dummy cycles, drive strength, etc + kDeviceConfigCmdType_QuadEnable, // !< Quad Enable command + kDeviceConfigCmdType_Spi2Xpi, // !< Switch from SPI to DPI/QPI/OPI mode + kDeviceConfigCmdType_Xpi2Spi, // !< Switch from DPI/QPI/OPI to SPI mode + kDeviceConfigCmdType_Spi2NoCmd, // !< Switch to 0-4-4/0-8-8 mode + kDeviceConfigCmdType_Reset, // !< Reset device command +}; + +// !@brief FlexSPI Memory Configuration Block +typedef struct _FlexSPIConfig +{ + uint32_t tag; // !< [0x000-0x003] Tag, fixed value 0x42464346UL + uint32_t version; // !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix + uint32_t reserved0; // !< [0x008-0x00b] Reserved for future use + uint8_t readSampleClkSrc; // !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 + uint8_t csHoldTime; // !< [0x00d-0x00d] CS hold time, default value: 3 + uint8_t csSetupTime; // !< [0x00e-0x00e] CS setup time, default value: 3 + uint8_t columnAddressWidth; // !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For + // ! Serial NAND, need to refer to datasheet + uint8_t deviceModeCfgEnable; // !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable + uint8_t deviceModeType; // !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, + // ! Generic configuration, etc. + uint16_t waitTimeCfgCommands; // !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for + // ! DPI/QPI/OPI switch or reset command + flexspi_lut_seq_t deviceModeSeq; // !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt + // ! sequence number, [31:16] Reserved + uint32_t deviceModeArg; // !< [0x018-0x01b] Argument/Parameter for device configuration + uint8_t configCmdEnable; // !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable + uint8_t configModeType[3]; // !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe + flexspi_lut_seq_t + configCmdSeqs[3]; // !< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq + uint32_t reserved1; // !< [0x02c-0x02f] Reserved for future use + uint32_t configCmdArgs[3]; // !< [0x030-0x03b] Arguments/Parameters for device Configuration commands + uint32_t reserved2; // !< [0x03c-0x03f] Reserved for future use + uint32_t controllerMiscOption; // !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more + // ! details + uint8_t deviceType; // !< [0x044-0x044] Device Type: See Flash Type Definition for more details + uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal + uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot + // ! Chapter for more details + uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot + // ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH + uint32_t reserved3[2]; // !< [0x048-0x04f] Reserved for future use + uint32_t sflashA1Size; // !< [0x050-0x053] Size of Flash connected to A1 + uint32_t sflashA2Size; // !< [0x054-0x057] Size of Flash connected to A2 + uint32_t sflashB1Size; // !< [0x058-0x05b] Size of Flash connected to B1 + uint32_t sflashB2Size; // !< [0x05c-0x05f] Size of Flash connected to B2 + uint32_t csPadSettingOverride; // !< [0x060-0x063] CS pad setting override value + uint32_t sclkPadSettingOverride; // !< [0x064-0x067] SCK pad setting override value + uint32_t dataPadSettingOverride; // !< [0x068-0x06b] data pad setting override value + uint32_t dqsPadSettingOverride; // !< [0x06c-0x06f] DQS pad setting override value + uint32_t timeoutInMs; // !< [0x070-0x073] Timeout threshold for read status command + uint32_t commandInterval; // !< [0x074-0x077] CS deselect interval between two commands + uint16_t dataValidTime[2]; // !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns + uint16_t busyOffset; // !< [0x07c-0x07d] Busy offset, valid value: 0-31 + uint16_t busyBitPolarity; // !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - + // ! busy flag is 0 when flash device is busy + uint32_t lookupTable[64]; // !< [0x080-0x17f] Lookup table holds Flash command sequences + flexspi_lut_seq_t lutCustomSeq[12]; // !< [0x180-0x1af] Customizable LUT Sequences + uint32_t reserved4[4]; // !< [0x1b0-0x1bf] Reserved for future use +} flexspi_mem_config_t; + +/* */ +#define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 +#define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 1 +#define NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD 2 +#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 3 +#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 4 +#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 +#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 6 +#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 7 +#define NOR_CMD_LUT_SEQ_IDX_READID 8 +#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM 9 +#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10 +#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 +#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12 + +#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0 +#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1 +#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS 2 +#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4 +#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6 +#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10 +#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP 12 + +/* + * Serial NOR configuration block + */ +typedef struct _flexspi_nor_config +{ + flexspi_mem_config_t memConfig; // !< Common memory configuration info via FlexSPI + uint32_t pageSize; // !< Page size of Serial NOR + uint32_t sectorSize; // !< Sector size of Serial NOR + uint8_t ipcmdSerialClkFreq; // !< Clock frequency for IP command + uint8_t isUniformBlockSize; // !< Sector/Block size is the same + uint8_t reserved0[2]; // !< Reserved for future use + uint8_t serialNorType; // !< Serial NOR Flash type: 0/1/2/3 + uint8_t needExitNoCmdMode; // !< Need to exit NoCmd mode before other IP command + uint8_t halfClkForNonReadCmd; // !< Half the Serial Clock for non-read command: true/false + uint8_t needRestoreNoCmdMode; // !< Need to Restore NoCmd mode after IP commmand execution + uint32_t blockSize; // !< Block size + uint32_t reserve2[11]; // !< Reserved for future use +} flexspi_nor_config_t; + +#define FLASH_BUSY_STATUS_POL 0 +#define FLASH_BUSY_STATUS_OFFSET 0 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif +#endif /* __FLEXSPI_FLASH_CONFIG__ */ diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.c b/ports/mimxrt/hal/flexspi_hyper_flash.c index fb71d4d94..c7b41658a 100644 --- a/ports/mimxrt/hal/flexspi_hyper_flash.c +++ b/ports/mimxrt/hal/flexspi_hyper_flash.c @@ -16,14 +16,15 @@ __attribute__((always_inline)) static inline void clock_set_div(clock_div_t divider, uint32_t value) { uint32_t busyShift; - busyShift = CCM_TUPLE_BUSY_SHIFT(divider); + busyShift = CCM_TUPLE_BUSY_SHIFT(divider); CCM_TUPLE_REG(CCM, divider) = (CCM_TUPLE_REG(CCM, divider) & (~CCM_TUPLE_MASK(divider))) | - (((uint32_t)((value) << CCM_TUPLE_SHIFT(divider))) & CCM_TUPLE_MASK(divider)); + (((uint32_t)((value) << CCM_TUPLE_SHIFT(divider))) & CCM_TUPLE_MASK(divider)); /* Clock switch need Handshake? */ if (CCM_NO_BUSY_WAIT != busyShift) { /* Wait until CCM internal handshake finish. */ - while (CCM->CDHIPR & (1U << busyShift)) {} + while (CCM->CDHIPR & (1U << busyShift)) { + } } } @@ -32,7 +33,7 @@ __attribute__((always_inline)) static inline void clock_control_gate(clock_ip_na uint32_t shift = ((uint32_t)name) & 0x1FU; volatile uint32_t *reg; - reg = ((volatile uint32_t *)&CCM->CCGR0) + index; + reg = ((volatile uint32_t *)&CCM->CCGR0) + index; *reg = ((*reg) & ~(3U << shift)) | (((uint32_t)value) << shift); } @@ -44,9 +45,9 @@ __attribute__((always_inline)) static inline void clock_disable_clock(clock_ip_n clock_control_gate(name, kCLOCK_ClockNotNeeded); } -#define DIV_PAGE_PGM 4 -#define DIV_ERASE_PGM 4 -#define DIV_READ 0 +#define DIV_PAGE_PGM 4 +#define DIV_ERASE_PGM 4 +#define DIV_READ 0 static void SetFlexSPIDiv(uint32_t div) __attribute__((section(".ram_functions"))); static void SetFlexSPIDiv(uint32_t div) { @@ -54,7 +55,7 @@ static void SetFlexSPIDiv(uint32_t div) { clock_disable_clock(kCLOCK_FlexSpi); clock_set_div(kCLOCK_FlexspiDiv, div); /* flexspi clock 332M, DDR mode, internal clock 166M. */ clock_enable_clock(kCLOCK_FlexSpi); - FLEXSPI_Enable(FLEXSPI, true); + FLEXSPI_Enable(FLEXSPI, true); } status_t flexspi_nor_hyperbus_read(FLEXSPI_Type *base, uint32_t addr, uint32_t *buffer, uint32_t bytes) __attribute__((section(".ram_functions"))); @@ -63,13 +64,13 @@ status_t flexspi_nor_hyperbus_read(FLEXSPI_Type *base, uint32_t addr, uint32_t * status_t status; flashXfer.deviceAddress = addr * 2; - flashXfer.port = kFLEXSPI_PortA1; - flashXfer.cmdType = kFLEXSPI_Read; - flashXfer.SeqNumber = 1; - flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA; - flashXfer.data = buffer; - flashXfer.dataSize = bytes; - status = FLEXSPI_TransferBlocking(base, &flashXfer); + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Read; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA; + flashXfer.data = buffer; + flashXfer.dataSize = bytes; + status = FLEXSPI_TransferBlocking(base, &flashXfer); return status; } @@ -80,13 +81,13 @@ status_t flexspi_nor_hyperbus_write(FLEXSPI_Type *base, uint32_t addr, uint32_t status_t status; flashXfer.deviceAddress = addr * 2; - flashXfer.port = kFLEXSPI_PortA1; - flashXfer.cmdType = kFLEXSPI_Write; - flashXfer.SeqNumber = 1; - flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA; - flashXfer.data = buffer; - flashXfer.dataSize = bytes; - status = FLEXSPI_TransferBlocking(base, &flashXfer); + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Write; + flashXfer.SeqNumber = 1; + flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA; + flashXfer.data = buffer; + flashXfer.dataSize = bytes; + status = FLEXSPI_TransferBlocking(base, &flashXfer); return status; } @@ -98,10 +99,10 @@ status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr) { /* Write enable */ flashXfer.deviceAddress = baseAddr; - flashXfer.port = kFLEXSPI_PortA1; - flashXfer.cmdType = kFLEXSPI_Command; - flashXfer.SeqNumber = 2; - flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Command; + flashXfer.SeqNumber = 2; + flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE; status = FLEXSPI_TransferBlocking(base, &flashXfer); @@ -117,12 +118,12 @@ status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) { flexspi_transfer_t flashXfer; flashXfer.deviceAddress = 0; - flashXfer.port = kFLEXSPI_PortA1; - flashXfer.cmdType = kFLEXSPI_Read; - flashXfer.SeqNumber = 2; - flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS; - flashXfer.data = &readValue; - flashXfer.dataSize = 2; + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Read; + flashXfer.SeqNumber = 2; + flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS; + flashXfer.data = &readValue; + flashXfer.dataSize = 2; do { status = FLEXSPI_TransferBlocking(base, &flashXfer); @@ -159,11 +160,11 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) { } flashXfer.deviceAddress = address; - flashXfer.port = kFLEXSPI_PortA1; - flashXfer.cmdType = kFLEXSPI_Command; - flashXfer.SeqNumber = 4; - flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR; - status = FLEXSPI_TransferBlocking(base, &flashXfer); + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Command; + flashXfer.SeqNumber = 4; + flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR; + status = FLEXSPI_TransferBlocking(base, &flashXfer); if (status != kStatus_Success) { return status; @@ -174,13 +175,13 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) { return status; } -status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size ) __attribute__((section(".ram_functions"))); +status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size) __attribute__((section(".ram_functions"))); status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size) { status_t status; flexspi_transfer_t flashXfer; /* Speed down flexspi clock */ - SetFlexSPIDiv(DIV_PAGE_PGM); + SetFlexSPIDiv(DIV_PAGE_PGM); /* Write enable */ status = flexspi_nor_write_enable(base, address); @@ -191,13 +192,13 @@ status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, co /* Prepare page program command */ flashXfer.deviceAddress = address; - flashXfer.port = kFLEXSPI_PortA1; - flashXfer.cmdType = kFLEXSPI_Write; - flashXfer.SeqNumber = 2; - flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM; - flashXfer.data = (uint32_t *)src; - flashXfer.dataSize = size; - status = FLEXSPI_TransferBlocking(base, &flashXfer); + flashXfer.port = kFLEXSPI_PortA1; + flashXfer.cmdType = kFLEXSPI_Write; + flashXfer.SeqNumber = 2; + flashXfer.seqIndex = HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM; + flashXfer.data = (uint32_t *)src; + flashXfer.dataSize = size; + status = FLEXSPI_TransferBlocking(base, &flashXfer); if (status != kStatus_Success) { return status; @@ -205,7 +206,7 @@ status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, co status = flexspi_nor_wait_bus_busy(base); - SetFlexSPIDiv(DIV_READ); + SetFlexSPIDiv(DIV_READ); return status; } @@ -219,7 +220,7 @@ status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base) { status_t status; uint32_t buffer[2]; uint8_t data[4] = {0x00, 0x98}; - status = flexspi_nor_hyperbus_write(base, 0x555, (uint32_t *)data, 2); + status = flexspi_nor_hyperbus_write(base, 0x555, (uint32_t *)data, 2); if (status != kStatus_Success) { return status; } @@ -238,7 +239,7 @@ status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base) { } // ASO Exit 0xF000 data[1] = 0xF0; - status = flexspi_nor_hyperbus_write(base, 0x0, (uint32_t *)data, 2); + status = flexspi_nor_hyperbus_write(base, 0x0, (uint32_t *)data, 2); if (status != kStatus_Success) { return status; } diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.h b/ports/mimxrt/hal/flexspi_hyper_flash.h index bba76c132..f340aec10 100644 --- a/ports/mimxrt/hal/flexspi_hyper_flash.h +++ b/ports/mimxrt/hal/flexspi_hyper_flash.h @@ -26,15 +26,14 @@ #ifndef MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H #define MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H -#include "mpconfigboard.h" #include "fsl_flexspi.h" -#include BOARD_FLASH_CONFIG_HEADER_H +#include "mpconfigboard.h" +#include "flexspi_flash_config.h" // Defined in boards flash_config.c extern flexspi_nor_config_t qspiflash_config; status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base); -void flexspi_hyper_flash_init(void); void flexspi_nor_update_lut(void); status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address); status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size); @@ -60,12 +59,4 @@ static inline uint32_t flexspi_get_frequency(void) { return fre; } -#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS 2 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE 4 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR 6 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM 10 -#define HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP 12 - #endif // MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H diff --git a/ports/mimxrt/hal/flexspi_nor_flash.c b/ports/mimxrt/hal/flexspi_nor_flash.c index a70d234d6..8c04150d1 100644 --- a/ports/mimxrt/hal/flexspi_nor_flash.c +++ b/ports/mimxrt/hal/flexspi_nor_flash.c @@ -41,8 +41,7 @@ void flexspi_nor_reset(FLEXSPI_Type *base) __attribute__((section(".ram_function void flexspi_nor_reset(FLEXSPI_Type *base) { // Using content of FLEXSPI_SoftwareReset directly to prevent issues when compiler does not inline function base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK; - while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) - { + while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) { } } @@ -63,7 +62,7 @@ status_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr) { return status; } -status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) __attribute__((section(".ram_functions"))) ; +status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) __attribute__((section(".ram_functions"))); status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) { /* Wait status ready. */ bool isBusy; @@ -103,7 +102,7 @@ status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) { return status; } -status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) __attribute__((section(".ram_functions"))) ; +status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) __attribute__((section(".ram_functions"))); status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) { flexspi_transfer_t flashXfer; status_t status; @@ -135,7 +134,7 @@ status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) { return status; } -status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) __attribute__((section(".ram_functions"))) ; +status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) __attribute__((section(".ram_functions"))); status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) { status_t status; flexspi_transfer_t flashXfer; @@ -166,7 +165,7 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) { return status; } -status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) __attribute__((section(".ram_functions"))) ; +status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) __attribute__((section(".ram_functions"))); status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) { status_t status; flexspi_transfer_t flashXfer; @@ -184,7 +183,7 @@ status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, co flashXfer.cmdType = kFLEXSPI_Write; flashXfer.SeqNumber = 1; flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD; - flashXfer.data = (uint32_t *) src; + flashXfer.data = (uint32_t *)src; flashXfer.dataSize = size; status = FLEXSPI_TransferBlocking(base, &flashXfer); @@ -199,7 +198,7 @@ status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, co return status; } -status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId) __attribute__((section(".ram_functions"))) ; +status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId) __attribute__((section(".ram_functions"))); status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId) { uint32_t temp; flexspi_transfer_t flashXfer; diff --git a/ports/mimxrt/hal/flexspi_nor_flash.h b/ports/mimxrt/hal/flexspi_nor_flash.h index c34df7416..c2c30876c 100644 --- a/ports/mimxrt/hal/flexspi_nor_flash.h +++ b/ports/mimxrt/hal/flexspi_nor_flash.h @@ -28,13 +28,12 @@ #include "fsl_flexspi.h" #include "mpconfigboard.h" -#include BOARD_FLASH_CONFIG_HEADER_H +#include "flexspi_flash_config.h" // Defined in boards flash_config.c extern flexspi_nor_config_t qspiflash_config; status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId); -status_t flexspi_nor_init(void); void flexspi_nor_update_lut(void); status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address); status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size); diff --git a/ports/mimxrt/hal/peripherals.h b/ports/mimxrt/hal/peripherals.h new file mode 100644 index 000000000..81036b0a2 --- /dev/null +++ b/ports/mimxrt/hal/peripherals.h @@ -0,0 +1 @@ +// Empty file, necessary for compilation with NXP MCU SDK diff --git a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c new file mode 100644 index 000000000..309755f86 --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.c @@ -0,0 +1,281 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_phydp83825.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the PHY PD83825 vendor defined registers. */ +#define PHY_PHYSTS_REG 0x10U /* Phy status register */ +#define PHY_BISCR_REG 0x16U /* RMII Config register. */ +#define PHY_RCSR_REG 0x17U /* RMII Config register. */ +#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control register 2. */ + +/*! @brief Defines the PHY DP82825 ID number. */ +#define PHY_CONTROL_ID1 0x2000U /*!< The PHY ID1 */ + +/*! @brief Defines the mask flag of operation mode in control registers */ +#define PHY_PHYSTS_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */ +#define PHY_PHYSTS_DUPLEX_MASK 0x0004U /*!< The PHY full duplex mask. */ +#define PHY_PHYSTS_100M_MASK 0x0002U /*!< The PHY 100M mask. */ +#define PHY_PHYSTS_LINK_MASK 0x0001U /*!< The PHY link up mask. */ + +#define PYH_RMII_CLOCK_SELECT 0x80 /* Select 50MHz clock */ +#define PHY_BISCR_REMOTELOOP_MASK 0x1FU /* !< The PHY remote loopback mask. */ +#define PHY_BISCR_REMOTELOOP_MODE 0x08U /* !< The PHY remote loopback mode. */ + +/*! @brief Defines the timeout macro. */ +#define PHY_READID_TIMEOUT_COUNT 1000U + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +const phy_operations_t phydp83825_ops = {.phyInit = PHY_DP83825_Init, + .phyWrite = PHY_DP83825_Write, + .phyRead = PHY_DP83825_Read, + .getAutoNegoStatus = PHY_DP83825_GetAutoNegotiationStatus, + .getLinkStatus = PHY_DP83825_GetLinkStatus, + .getLinkSpeedDuplex = PHY_DP83825_GetLinkSpeedDuplex, + .setLinkSpeedDuplex = PHY_DP83825_SetLinkSpeedDuplex, + .enableLoopback = PHY_DP83825_EnableLoopback}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_DP83825_Init(phy_handle_t *handle, const phy_config_t *config) { + uint32_t counter = PHY_READID_TIMEOUT_COUNT; + status_t result = kStatus_Success; + uint32_t regValue = 0; + + /* Init MDIO interface. */ + MDIO_Init(handle->mdioHandle); + + /* Assign phy address. */ + handle->phyAddr = config->phyAddr; + + /* Check PHY ID. */ + do + { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + counter--; + } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U)); + + if (counter == 0U) { + return kStatus_Fail; + } + + /* Reset PHY. */ + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + if (result == kStatus_Success) { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_RCSR_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_RCSR_REG, (regValue | PYH_RMII_CLOCK_SELECT)); + if (result != kStatus_Success) { + return result; + } + + if (config->autoNeg) { + /* Set the auto-negotiation then start it. */ + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG, + (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | + PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK)); + if (result == kStatus_Success) { + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } else { + /* This PHY only supports 10/100M speed. */ + assert(config->speed <= kPHY_Speed100M); + + /* Disable isolate mode */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + regValue &= ~PHY_BCTL_ISOLATE_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) { + return result; + } + + /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */ + result = PHY_DP83825_SetLinkSpeedDuplex(handle, config->speed, config->duplex); + } + } + return result; +} + +status_t PHY_DP83825_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data); +} + +status_t PHY_DP83825_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) { + return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr); +} + +status_t PHY_DP83825_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + *status = false; + + /* Check auto negotiation complete. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) { + if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) { + *status = true; + } + } + return result; +} + +status_t PHY_DP83825_GetLinkStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + /* Read the basic status register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) { + if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) { + /* Link up. */ + *status = true; + } else { + /* Link down. */ + *status = false; + } + } + return result; +} + +status_t PHY_DP83825_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) { + assert(!((speed == NULL) && (duplex == NULL))); + + status_t result; + uint32_t regValue; + uint32_t flag; + + /* Read the control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, ®Value); + if (result == kStatus_Success) { + if (speed != NULL) { + flag = regValue & PHY_PHYSTS_100M_MASK; + if (flag) { + *speed = kPHY_Speed10M; + } else { + *speed = kPHY_Speed100M; + } + } + + if (duplex != NULL) { + flag = regValue & PHY_PHYSTS_DUPLEX_MASK; + if (flag) { + *duplex = kPHY_FullDuplex; + } else { + *duplex = kPHY_HalfDuplex; + } + } + } + return result; +} + +status_t PHY_DP83825_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) { + /* This PHY only supports 10/100M speed. */ + assert(speed <= kPHY_Speed100M); + + status_t result; + uint32_t regValue; + + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + /* Disable the auto-negotiation and set according to user-defined configuration. */ + regValue &= ~PHY_BCTL_AUTONEG_MASK; + if (speed == kPHY_Speed100M) { + regValue |= PHY_BCTL_SPEED0_MASK; + } else { + regValue &= ~PHY_BCTL_SPEED0_MASK; + } + if (duplex == kPHY_FullDuplex) { + regValue |= PHY_BCTL_DUPLEX_MASK; + } else { + regValue &= ~PHY_BCTL_DUPLEX_MASK; + } + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + return result; +} +status_t PHY_DP83825_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) { + /* This PHY only supports local/remote loopback and 10/100M speed. */ + assert(mode <= kPHY_RemoteLoop); + assert(speed <= kPHY_Speed100M); + + status_t result = kStatus_Success; + uint32_t regValue; + + /* Set the loop mode. */ + if (enable) { + if (mode == kPHY_LocalLoop) { + if (speed == kPHY_Speed100M) { + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } else { + regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } else { + /* Remote loopback only supports 100M full-duplex. */ + assert(speed == kPHY_Speed100M); + + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) { + return result; + } + /* Set the remote loopback bit. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG, ®Value); + if (result == kStatus_Success) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG, + (regValue & ~PHY_BISCR_REMOTELOOP_MASK) | PHY_BISCR_REMOTELOOP_MODE); + } + } + } else { + /* Disable the loop mode. */ + if (mode != kPHY_LocalLoop) { + /* First read the current status in control one register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG, ®Value); + if (result == kStatus_Success) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BISCR_REG, + (regValue & ~PHY_BISCR_REMOTELOOP_MASK)); + } + } + /* First read the current status in control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + regValue &= ~PHY_BCTL_LOOP_MASK; + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (regValue | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + + return result; +} diff --git a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h new file mode 100644 index 000000000..9d6b4fdf7 --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h @@ -0,0 +1,163 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/***************************************************************************** + * PHY DP83825 driver change log + *****************************************************************************/ + +/*! +@page driver_log Driver Change Log + +@section phyksz8081 PHYDP83825 + The current PHYDP83825 driver version is 2.0.0. + + - 2.0.0 + - Initial version. +*/ + +#ifndef _FSL_DP83825_H_ +#define _FSL_DP83825_H_ + +#include "fsl_phy.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY driver version */ +#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) + +/*! @brief PHY operations structure. */ +extern const phy_operations_t phydp83825_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize PHY. + * + * @param handle PHY device handle. + * @param config Pointer to structure of phy_config_t. + * @retval kStatus_Success PHY initialization succeeds + * @retval kStatus_Fail PHY initialization fails + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83825_Init(phy_handle_t *handle, const phy_config_t *config); + +/*! + * @brief PHY Write function. This function writes data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83825_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data); + +/*! + * @brief PHY Read function. This interface read data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83825_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Gets the PHY auto-negotiation status. + * + * @param handle PHY device handle. + * @param status The auto-negotiation status of the PHY. + * - true the auto-negotiation is over. + * - false the auto-negotiation is on-going or not started. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83825_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link status. + * + * @param handle PHY device handle. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY gets link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83825_GetLinkStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @brief This function gets the speed and duplex mode of PHY. User can give one of speed + * and duplex address paramter and set the other as NULL if only wants to get one of them. + * + * @param handle PHY device handle. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY gets link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83825_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex); + +/*! + * @brief Sets the PHY link speed and duplex. + * + * @param handle PHY device handle. + * @param speed Specified PHY link speed. + * @param duplex Specified PHY link duplex. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83825_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex); + +/*! + * @brief Enables/disables PHY loopback. + * + * @param handle PHY device handle. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * All loopback modes should not be set together, when one loopback mode is set + * another should be disabled. + * @param speed PHY speed for loopback mode. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY loopback success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83825_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_DP83825_H_ */ diff --git a/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c new file mode 100644 index 000000000..07ce6d1f7 --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.c @@ -0,0 +1,254 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_phydp83848.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the PHY PD83848 vendor defined registers. */ +#define PHY_PHYSTS_REG 0x10U /* Phy status register */ +#define PHY_RBR_REG 0x17U /* RMII Config register. */ + +/*! @brief Defines the PHY DP82825 ID number. */ +#define PHY_CONTROL_ID1 0x2000U /*!< The PHY ID1 */ + +/*! @brief Defines the mask flag of operation mode in control registers */ +#define PHY_PHYSTS_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */ +#define PHY_PHYSTS_DUPLEX_MASK 0x0004U /*!< The PHY full duplex mask. */ +#define PHY_PHYSTS_100M_MASK 0x0002U /*!< The PHY 100M mask. */ +#define PHY_PHYSTS_LINK_MASK 0x0001U /*!< The PHY link up mask. */ + +#define PHY_RMII_MODE 0x20 +#define PHY_RMII_REV1_0 0x10 + +/*! @brief Defines the timeout macro. */ +#define PHY_READID_TIMEOUT_COUNT 1000U + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +const phy_operations_t phydp83848_ops = {.phyInit = PHY_DP83848_Init, + .phyWrite = PHY_DP83848_Write, + .phyRead = PHY_DP83848_Read, + .getAutoNegoStatus = PHY_DP83848_GetAutoNegotiationStatus, + .getLinkStatus = PHY_DP83848_GetLinkStatus, + .getLinkSpeedDuplex = PHY_DP83848_GetLinkSpeedDuplex, + .setLinkSpeedDuplex = PHY_DP83848_SetLinkSpeedDuplex, + .enableLoopback = PHY_DP83848_EnableLoopback}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_DP83848_Init(phy_handle_t *handle, const phy_config_t *config) { + uint32_t counter = PHY_READID_TIMEOUT_COUNT; + status_t result = kStatus_Success; + uint32_t regValue = 0; + + /* Init MDIO interface. */ + MDIO_Init(handle->mdioHandle); + + /* Assign phy address. */ + handle->phyAddr = config->phyAddr; + + /* Check PHY ID. */ + do + { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + counter--; + } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U)); + + if (counter == 0U) { + return kStatus_Fail; + } + + /* Reset PHY. */ + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + if (result == kStatus_Success) { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_RBR_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_RBR_REG, (regValue | PHY_RMII_MODE | PHY_RMII_REV1_0)); + if (result != kStatus_Success) { + return result; + } + + if (config->autoNeg) { + /* Set the auto-negotiation then start it. */ + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG, + (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | + PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK)); + if (result == kStatus_Success) { + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } else { + /* This PHY only supports 10/100M speed. */ + assert(config->speed <= kPHY_Speed100M); + + /* Disable isolate mode */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + regValue &= ~PHY_BCTL_ISOLATE_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) { + return result; + } + + /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */ + result = PHY_DP83848_SetLinkSpeedDuplex(handle, config->speed, config->duplex); + } + } + return result; +} + +status_t PHY_DP83848_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data); +} + +status_t PHY_DP83848_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) { + return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr); +} + +status_t PHY_DP83848_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + *status = false; + + /* Check auto negotiation complete. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) { + if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) { + *status = true; + } + } + return result; +} + +status_t PHY_DP83848_GetLinkStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + /* Read the basic status register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) { + if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) { + /* Link up. */ + *status = true; + } else { + /* Link down. */ + *status = false; + } + } + return result; +} + +status_t PHY_DP83848_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) { + assert(!((speed == NULL) && (duplex == NULL))); + + status_t result; + uint32_t regValue; + uint32_t flag; + + /* Read the control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, ®Value); + if (result == kStatus_Success) { + if (speed != NULL) { + flag = regValue & PHY_PHYSTS_100M_MASK; + if (flag) { + *speed = kPHY_Speed10M; + } else { + *speed = kPHY_Speed100M; + } + } + + if (duplex != NULL) { + flag = regValue & PHY_PHYSTS_DUPLEX_MASK; + if (flag) { + *duplex = kPHY_FullDuplex; + } else { + *duplex = kPHY_HalfDuplex; + } + } + } + return result; +} + +status_t PHY_DP83848_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) { + /* This PHY only supports 10/100M speed. */ + assert(speed <= kPHY_Speed100M); + + status_t result; + uint32_t regValue; + + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + /* Disable the auto-negotiation and set according to user-defined configuration. */ + regValue &= ~PHY_BCTL_AUTONEG_MASK; + if (speed == kPHY_Speed100M) { + regValue |= PHY_BCTL_SPEED0_MASK; + } else { + regValue &= ~PHY_BCTL_SPEED0_MASK; + } + if (duplex == kPHY_FullDuplex) { + regValue |= PHY_BCTL_DUPLEX_MASK; + } else { + regValue &= ~PHY_BCTL_DUPLEX_MASK; + } + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + return result; +} +status_t PHY_DP83848_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) { + /* This PHY only supports local/remote loopback and 10/100M speed. */ + assert(mode <= kPHY_RemoteLoop); + assert(speed <= kPHY_Speed100M); + + status_t result = kStatus_Success; + uint32_t regValue; + + /* Set the loop mode. */ + if (enable) { + if (mode == kPHY_LocalLoop) { + if (speed == kPHY_Speed100M) { + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } else { + regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + } else { + /* First read the current status in control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + regValue &= ~PHY_BCTL_LOOP_MASK; + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (regValue | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + + return result; +} diff --git a/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h new file mode 100644 index 000000000..7ccc260f7 --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h @@ -0,0 +1,163 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/***************************************************************************** + * PHY DP83848 driver change log + *****************************************************************************/ + +/*! +@page driver_log Driver Change Log + +@section phyksz8081 PHYDP83848 + The current PHYDP83848 driver version is 2.0.0. + + - 2.0.0 + - Initial version. +*/ + +#ifndef _FSL_DP83848_H_ +#define _FSL_DP83848_H_ + +#include "fsl_phy.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY driver version */ +#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) + +/*! @brief PHY operations structure. */ +extern const phy_operations_t phydp83848_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize PHY. + * + * @param handle PHY device handle. + * @param config Pointer to structure of phy_config_t. + * @retval kStatus_Success PHY initialization succeeds + * @retval kStatus_Fail PHY initialization fails + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83848_Init(phy_handle_t *handle, const phy_config_t *config); + +/*! + * @brief PHY Write function. This function writes data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83848_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data); + +/*! + * @brief PHY Read function. This interface read data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83848_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Gets the PHY auto-negotiation status. + * + * @param handle PHY device handle. + * @param status The auto-negotiation status of the PHY. + * - true the auto-negotiation is over. + * - false the auto-negotiation is on-going or not started. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83848_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link status. + * + * @param handle PHY device handle. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY gets link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83848_GetLinkStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @brief This function gets the speed and duplex mode of PHY. User can give one of speed + * and duplex address paramter and set the other as NULL if only wants to get one of them. + * + * @param handle PHY device handle. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY gets link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83848_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex); + +/*! + * @brief Sets the PHY link speed and duplex. + * + * @param handle PHY device handle. + * @param speed Specified PHY link speed. + * @param duplex Specified PHY link duplex. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83848_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex); + +/*! + * @brief Enables/disables PHY loopback. + * + * @param handle PHY device handle. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * All loopback modes should not be set together, when one loopback mode is set + * another should be disabled. + * @param speed PHY speed for loopback mode. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY loopback success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_DP83848_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_DP83848_H_ */ diff --git a/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c new file mode 100644 index 000000000..32cabacdb --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.c @@ -0,0 +1,284 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_phyksz8081.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the PHY KSZ8081 vendor defined registers. */ +#define PHY_CONTROL1_REG 0x1EU /*!< The PHY control one register. */ +#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control two register. */ + +/*! @brief Defines the PHY KSZ8081 ID number. */ +#define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1 */ + +/*! @brief Defines the mask flag of operation mode in control registers */ +#define PHY_CTL2_REMOTELOOP_MASK 0x0004U /*!< The PHY remote loopback mask. */ +#define PHY_CTL2_REFCLK_SELECT_MASK 0x0080U /*!< The PHY RMII reference clock select. */ +#define PHY_CTL1_10HALFDUPLEX_MASK 0x0001U /*!< The PHY 10M half duplex mask. */ +#define PHY_CTL1_100HALFDUPLEX_MASK 0x0002U /*!< The PHY 100M half duplex mask. */ +#define PHY_CTL1_10FULLDUPLEX_MASK 0x0005U /*!< The PHY 10M full duplex mask. */ +#define PHY_CTL1_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */ +#define PHY_CTL1_SPEEDUPLX_MASK 0x0007U /*!< The PHY speed and duplex mask. */ +#define PHY_CTL1_ENERGYDETECT_MASK 0x10U /*!< The PHY signal present on rx differential pair. */ +#define PHY_CTL1_LINKUP_MASK 0x100U /*!< The PHY link up. */ +#define PHY_LINK_READY_MASK (PHY_CTL1_ENERGYDETECT_MASK | PHY_CTL1_LINKUP_MASK) + +/*! @brief Defines the timeout macro. */ +#define PHY_READID_TIMEOUT_COUNT 1000U + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +const phy_operations_t phyksz8081_ops = {.phyInit = PHY_KSZ8081_Init, + .phyWrite = PHY_KSZ8081_Write, + .phyRead = PHY_KSZ8081_Read, + .getAutoNegoStatus = PHY_KSZ8081_GetAutoNegotiationStatus, + .getLinkStatus = PHY_KSZ8081_GetLinkStatus, + .getLinkSpeedDuplex = PHY_KSZ8081_GetLinkSpeedDuplex, + .setLinkSpeedDuplex = PHY_KSZ8081_SetLinkSpeedDuplex, + .enableLoopback = PHY_KSZ8081_EnableLoopback}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_KSZ8081_Init(phy_handle_t *handle, const phy_config_t *config) { + uint32_t counter = PHY_READID_TIMEOUT_COUNT; + status_t result = kStatus_Success; + uint32_t regValue = 0; + + /* Init MDIO interface. */ + MDIO_Init(handle->mdioHandle); + + /* Assign phy address. */ + handle->phyAddr = config->phyAddr; + + /* Check PHY ID. */ + do + { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + counter--; + } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U)); + + if (counter == 0U) { + return kStatus_Fail; + } + + /* Reset PHY. */ + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + if (result == kStatus_Success) { + #if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE) + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, (regValue | PHY_CTL2_REFCLK_SELECT_MASK)); + if (result != kStatus_Success) { + return result; + } + #endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */ + + if (config->autoNeg) { + /* Set the auto-negotiation then start it. */ + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG, + (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | + PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK)); + if (result == kStatus_Success) { + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } else { + /* This PHY only supports 10/100M speed. */ + assert(config->speed <= kPHY_Speed100M); + + /* Disable isolate mode */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + regValue &= ~PHY_BCTL_ISOLATE_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) { + return result; + } + + /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */ + result = PHY_KSZ8081_SetLinkSpeedDuplex(handle, config->speed, config->duplex); + } + } + return result; +} + +status_t PHY_KSZ8081_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data); +} + +status_t PHY_KSZ8081_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) { + return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr); +} + +status_t PHY_KSZ8081_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + *status = false; + + /* Check auto negotiation complete. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) { + if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) { + *status = true; + } + } + return result; +} + +status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + /* Read the basic status register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) { + if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) { + /* Link up. */ + *status = true; + } else { + /* Link down. */ + *status = false; + } + } + return result; +} + +status_t PHY_KSZ8081_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) { + assert(!((speed == NULL) && (duplex == NULL))); + + status_t result; + uint32_t regValue; + uint32_t flag; + + /* Read the control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL1_REG, ®Value); + if (result == kStatus_Success) { + if (speed != NULL) { + flag = regValue & PHY_CTL1_SPEEDUPLX_MASK; + if ((PHY_CTL1_100HALFDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag)) { + *speed = kPHY_Speed100M; + } else { + *speed = kPHY_Speed10M; + } + } + + if (duplex != NULL) { + flag = regValue & PHY_CTL1_SPEEDUPLX_MASK; + if ((PHY_CTL1_10FULLDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag)) { + *duplex = kPHY_FullDuplex; + } else { + *duplex = kPHY_HalfDuplex; + } + } + } + return result; +} + +status_t PHY_KSZ8081_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) { + /* This PHY only supports 10/100M speed. */ + assert(speed <= kPHY_Speed100M); + + status_t result; + uint32_t regValue; + + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + /* Disable the auto-negotiation and set according to user-defined configuration. */ + regValue &= ~PHY_BCTL_AUTONEG_MASK; + if (speed == kPHY_Speed100M) { + regValue |= PHY_BCTL_SPEED0_MASK; + } else { + regValue &= ~PHY_BCTL_SPEED0_MASK; + } + if (duplex == kPHY_FullDuplex) { + regValue |= PHY_BCTL_DUPLEX_MASK; + } else { + regValue &= ~PHY_BCTL_DUPLEX_MASK; + } + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + return result; +} + +status_t PHY_KSZ8081_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) { + /* This PHY only supports local/remote loopback and 10/100M speed. */ + assert(mode <= kPHY_RemoteLoop); + assert(speed <= kPHY_Speed100M); + + status_t result; + uint32_t regValue; + + /* Set the loop mode. */ + if (enable) { + if (mode == kPHY_LocalLoop) { + if (speed == kPHY_Speed100M) { + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } else { + regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } else { + /* Remote loopback only supports 100M full-duplex. */ + assert(speed == kPHY_Speed100M); + + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) { + return result; + } + /* Set the remote loopback bit. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, ®Value); + if (result == kStatus_Success) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, + (regValue | PHY_CTL2_REMOTELOOP_MASK)); + } + } + } else { + /* Disable the loop mode. */ + if (mode == kPHY_LocalLoop) { + /* First read the current status in control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + regValue &= ~PHY_BCTL_LOOP_MASK; + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (regValue | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } else { + /* First read the current status in control one register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, ®Value); + if (result == kStatus_Success) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, + (regValue & ~PHY_CTL2_REMOTELOOP_MASK)); + } + } + } + return result; +} diff --git a/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h new file mode 100644 index 000000000..5b93c5698 --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h @@ -0,0 +1,163 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/***************************************************************************** + * PHY KSZ8081 driver change log + *****************************************************************************/ + +/*! +@page driver_log Driver Change Log + +@section phyksz8081 PHYKSZ8081 + The current PHYKSZ8081 driver version is 2.0.0. + + - 2.0.0 + - Initial version. +*/ + +#ifndef _FSL_PHYKSZ8081_H_ +#define _FSL_PHYKSZ8081_H_ + +#include "fsl_phy.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY driver version */ +#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) + +/*! @brief PHY operations structure. */ +extern const phy_operations_t phyksz8081_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize PHY. + * + * @param handle PHY device handle. + * @param config Pointer to structure of phy_config_t. + * @retval kStatus_Success PHY initialization succeeds + * @retval kStatus_Fail PHY initialization fails + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_Init(phy_handle_t *handle, const phy_config_t *config); + +/*! + * @brief PHY Write function. This function writes data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data); + +/*! + * @brief PHY Read function. This interface read data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Gets the PHY auto-negotiation status. + * + * @param handle PHY device handle. + * @param status The auto-negotiation status of the PHY. + * - true the auto-negotiation is over. + * - false the auto-negotiation is on-going or not started. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link status. + * + * @param handle PHY device handle. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY gets link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @brief This function gets the speed and duplex mode of PHY. User can give one of speed + * and duplex address paramter and set the other as NULL if only wants to get one of them. + * + * @param handle PHY device handle. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY gets link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex); + +/*! + * @brief Sets the PHY link speed and duplex. + * + * @param handle PHY device handle. + * @param speed Specified PHY link speed. + * @param duplex Specified PHY link duplex. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex); + +/*! + * @brief Enables/disables PHY loopback. + * + * @param handle PHY device handle. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * All loopback modes should not be set together, when one loopback mode is set + * another should be disabled. + * @param speed PHY speed for loopback mode. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY loopback success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_PHYKSZ8081_H_ */ diff --git a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c new file mode 100644 index 000000000..e141ebd51 --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.c @@ -0,0 +1,271 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_phylan8720.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the PHY LAN8720 vendor defined registers. */ +#define PHY_PHYSTS_REG 0x1FU /* Phy status register */ +#define PHY_MCSR_REG 0x11U /* Mode Control/Status Register for loopback */ + +/*! @brief Defines the PHY LAN8720 ID number. */ +#define PHY_CONTROL_ID1 0x07U /*!< The PHY ID1 */ + +/*! @brief Defines the mask flag of operation mode in control registers */ +#define PHY_PHYSTS_MASK 0x001CU /*!< The PHY Status mask. */ +#define PHY_PHYSTS_DUPLEX_MASK 0x0010U /*!< The PHY full duplex mask. */ +#define PHY_PHYSTS_100M_MASK 0x000CU /*!< The PHY 100M mask. */ +#define PHY_PHYSTS_100M_FLAG 0x0008U /*!< The PHY 100M flag. */ +#define PHY_PHYSTS_LINK_MASK 0x0001U /*!< The PHY link up mask. */ + +#define PHY_MCSR_REMOTELOOP_MASK 0x100U /* !< The PHY remote loopback mask. */ +#define PHY_MCSR_REMOTELOOP_MODE 0x100U /* !< The PHY remote loopback mode. */ + +/*! @brief Defines the timeout macro. */ +#define PHY_READID_TIMEOUT_COUNT 1000U + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +const phy_operations_t phylan8720_ops = {.phyInit = PHY_LAN8720_Init, + .phyWrite = PHY_LAN8720_Write, + .phyRead = PHY_LAN8720_Read, + .getAutoNegoStatus = PHY_LAN8720_GetAutoNegotiationStatus, + .getLinkStatus = PHY_LAN8720_GetLinkStatus, + .getLinkSpeedDuplex = PHY_LAN8720_GetLinkSpeedDuplex, + .setLinkSpeedDuplex = PHY_LAN8720_SetLinkSpeedDuplex, + .enableLoopback = PHY_LAN8720_EnableLoopback}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_LAN8720_Init(phy_handle_t *handle, const phy_config_t *config) { + uint32_t counter = PHY_READID_TIMEOUT_COUNT; + status_t result = kStatus_Success; + uint32_t regValue = 0; + + /* Init MDIO interface. */ + MDIO_Init(handle->mdioHandle); + + /* Assign phy address. */ + handle->phyAddr = config->phyAddr; + + /* Check PHY ID. */ + do + { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + counter--; + } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U)); + + if (counter == 0U) { + return kStatus_Fail; + } + + /* Reset PHY. */ + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + if (result == kStatus_Success) { + if (config->autoNeg) { + /* Set the auto-negotiation then start it. */ + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG, + (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | + PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK)); + if (result == kStatus_Success) { + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } else { + /* This PHY only supports 10/100M speed. */ + assert(config->speed <= kPHY_Speed100M); + + /* Disable isolate mode */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result != kStatus_Success) { + return result; + } + regValue &= ~PHY_BCTL_ISOLATE_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) { + return result; + } + + /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */ + result = PHY_LAN8720_SetLinkSpeedDuplex(handle, config->speed, config->duplex); + } + } + return result; +} + +status_t PHY_LAN8720_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data); +} + +status_t PHY_LAN8720_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) { + return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr); +} + +status_t PHY_LAN8720_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + *status = false; + + /* Check auto negotiation complete. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) { + if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) { + *status = true; + } + } + return result; +} + +status_t PHY_LAN8720_GetLinkStatus(phy_handle_t *handle, bool *status) { + assert(status); + + status_t result; + uint32_t regValue; + + /* Read the basic status register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) { + if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) { + /* Link up. */ + *status = true; + } else { + /* Link down. */ + *status = false; + } + } + return result; +} + +status_t PHY_LAN8720_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) { + assert(!((speed == NULL) && (duplex == NULL))); + + status_t result; + uint32_t regValue; + uint32_t flag; + + /* Read the control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_PHYSTS_REG, ®Value); + if (result == kStatus_Success) { + regValue &= PHY_PHYSTS_MASK; + if (speed != NULL) { + flag = regValue & PHY_PHYSTS_100M_MASK; + if (flag == PHY_PHYSTS_100M_FLAG) { + *speed = kPHY_Speed100M; + } else { + *speed = kPHY_Speed10M; + } + } + + if (duplex != NULL) { + flag = regValue & PHY_PHYSTS_DUPLEX_MASK; + if (flag) { + *duplex = kPHY_FullDuplex; + } else { + *duplex = kPHY_HalfDuplex; + } + } + } + return result; +} + +status_t PHY_LAN8720_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) { + /* This PHY only supports 10/100M speed. */ + assert(speed <= kPHY_Speed100M); + + status_t result; + uint32_t regValue; + + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + /* Disable the auto-negotiation and set according to user-defined configuration. */ + regValue &= ~PHY_BCTL_AUTONEG_MASK; + if (speed == kPHY_Speed100M) { + regValue |= PHY_BCTL_SPEED0_MASK; + } else { + regValue &= ~PHY_BCTL_SPEED0_MASK; + } + if (duplex == kPHY_FullDuplex) { + regValue |= PHY_BCTL_DUPLEX_MASK; + } else { + regValue &= ~PHY_BCTL_DUPLEX_MASK; + } + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + return result; +} + +status_t PHY_LAN8720_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) { + /* This PHY only supports local/remote loopback and 10/100M speed. */ + assert(mode <= kPHY_RemoteLoop); + assert(speed <= kPHY_Speed100M); + + status_t result = kStatus_Success; + uint32_t regValue; + + /* Set the loop mode. */ + if (enable) { + if (mode == kPHY_LocalLoop) { + if (speed == kPHY_Speed100M) { + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } else { + regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } else { + /* Remote loopback only supports 100M full-duplex. */ + assert(speed == kPHY_Speed100M); + + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) { + return result; + } + /* Set the remote loopback bit. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG, ®Value); + if (result == kStatus_Success) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG, + (regValue & ~PHY_MCSR_REMOTELOOP_MASK) | PHY_MCSR_REMOTELOOP_MODE); + } + } + } else { + /* Disable the loop mode. */ + if (mode != kPHY_LocalLoop) { + /* First read the current status in control one register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG, ®Value); + if (result == kStatus_Success) { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MCSR_REG, + (regValue & ~PHY_MCSR_REMOTELOOP_MASK)); + } + } + /* First read the current status in control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) { + regValue &= ~PHY_BCTL_LOOP_MASK; + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (regValue | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + + return result; +} diff --git a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h new file mode 100644 index 000000000..2e8b4e363 --- /dev/null +++ b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h @@ -0,0 +1,163 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/***************************************************************************** + * PHY KSZ8081 driver change log + *****************************************************************************/ + +/*! +@page driver_log Driver Change Log + +@section phylan8720 PHYLAN8720 + The current PHYLAN8720 driver version is 2.0.0. + + - 2.0.0 + - Initial version. +*/ + +#ifndef _FSL_PHYLAN8720_H_ +#define _FSL_PHYLAN8720_H_ + +#include "fsl_phy.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY driver version */ +#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) + +/*! @brief PHY operations structure. */ +extern const phy_operations_t phylan8720_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize PHY. + * + * @param handle PHY device handle. + * @param config Pointer to structure of phy_config_t. + * @retval kStatus_Success PHY initialization succeeds + * @retval kStatus_Fail PHY initialization fails + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_LAN8720_Init(phy_handle_t *handle, const phy_config_t *config); + +/*! + * @brief PHY Write function. This function writes data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_LAN8720_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data); + +/*! + * @brief PHY Read function. This interface read data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_LAN8720_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Gets the PHY auto-negotiation status. + * + * @param handle PHY device handle. + * @param status The auto-negotiation status of the PHY. + * - true the auto-negotiation is over. + * - false the auto-negotiation is on-going or not started. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_LAN8720_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link status. + * + * @param handle PHY device handle. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY gets link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_LAN8720_GetLinkStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @brief This function gets the speed and duplex mode of PHY. User can give one of speed + * and duplex address paramter and set the other as NULL if only wants to get one of them. + * + * @param handle PHY device handle. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY gets link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_LAN8720_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex); + +/*! + * @brief Sets the PHY link speed and duplex. + * + * @param handle PHY device handle. + * @param speed Specified PHY link speed. + * @param duplex Specified PHY link duplex. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_LAN8720_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex); + +/*! + * @brief Enables/disables PHY loopback. + * + * @param handle PHY device handle. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * All loopback modes should not be set together, when one loopback mode is set + * another should be disabled. + * @param speed PHY speed for loopback mode. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY loopback success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_LAN8720_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_PHYLAN8720_H_ */ diff --git a/ports/mimxrt/hal/phy/fsl_mdio.h b/ports/mimxrt/hal/phy/fsl_mdio.h new file mode 100644 index 000000000..6bfee2a24 --- /dev/null +++ b/ports/mimxrt/hal/phy/fsl_mdio.h @@ -0,0 +1,125 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_MDIO_H_ +#define _FSL_MDIO_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the timeout macro. */ +#if defined(MDIO_TIMEOUT_COUNT_NUMBER) && MDIO_TIMEOUT_COUNT_NUMBER +#define MDIO_TIMEOUT_COUNT MDIO_TIMEOUT_COUNT_NUMBER +#endif + +/*! @brief Defines the PHY status. */ +enum _mdio_status +{ + kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 0), /*!< ENET PHY SMI visit timeout. */ +}; + +typedef struct _mdio_operations mdio_operations_t; + +/*! @brief MDIO resource. */ +typedef struct _mdio_resource +{ + void *base; /*!< ENET Ip register base. */ + uint32_t csrClock_Hz; /*!< ENET CSR clock. */ +} mdio_resource_t; + +/*! @brief MDIO handle. */ +typedef struct _mdio_handle +{ + mdio_resource_t resource; + const mdio_operations_t *ops; +} mdio_handle_t; + +/*! @brief Camera receiver operations. */ +struct _mdio_operations +{ + void (*mdioInit)(mdio_handle_t *handle); /*!< MDIO interface init. */ + status_t (*mdioWrite)(mdio_handle_t *handle, + uint32_t phyAddr, + uint32_t devAddr, + uint32_t data); /*!< MDIO write data. */ + status_t (*mdioRead)(mdio_handle_t *handle, + uint32_t phyAddr, + uint32_t devAddr, + uint32_t *dataPtr); /*!< MDIO read data. */ + status_t (*mdioWriteExt)(mdio_handle_t *handle, + uint32_t phyAddr, + uint32_t devAddr, + uint32_t data); /*!< MDIO write data. */ + status_t (*mdioReadExt)(mdio_handle_t *handle, + uint32_t phyAddr, + uint32_t devAddr, + uint32_t *dataPtr); /*!< MDIO read data. */ +}; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif +/*! + * @name MDIO Driver + * @{ + */ + +/*! + * @brief MDIO Write function. This function write data over the SMI to + * the specified MDIO register. This function is called by all MDIO interfaces. + * + * @param handle MDIO device handle. + * @retval kStatus_Success MDIO write success + * @retval kStatus_MDIO_SMIVisitTimeout MDIO SMI visit time out + */ +static inline void MDIO_Init(mdio_handle_t *handle) { + handle->ops->mdioInit(handle); +} + +/*! + * @brief MDIO Write function. This function write data over the SMI to + * the specified MDIO register. This function is called by all MDIO interfaces. + * + * @param handle MDIO device handle. + * @param phyAddr MDIO PHY address handle. + * @param devAddr The PHY device register. + * @param data The data written to the MDIO register. + * @retval kStatus_Success MDIO write success + * @retval kStatus_MDIO_SMIVisitTimeout MDIO SMI visit time out + */ +static inline status_t MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data) { + return handle->ops->mdioWrite(handle, phyAddr, devAddr, data); +} + +/*! + * @brief MDIO Read function. This interface read data over the SMI from the + * specified MDIO register. This function is called by all MDIO interfaces. + * + * @param handle MDIO device handle. + * @param phyAddr MDIO PHY address handle. + * @param devAddr The PHY device register. + * @param dataPtr The address to store the data read from the MDIO register. + * @retval kStatus_Success MDIO read success + * @retval kStatus_MDIO_SMIVisitTimeout MDIO SMI visit time out + */ +static inline status_t MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr) { + return handle->ops->mdioRead(handle, phyAddr, devAddr, dataPtr); +} + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/ports/mimxrt/hal/phy/fsl_phy.h b/ports/mimxrt/hal/phy/fsl_phy.h new file mode 100644 index 000000000..6a022d4ea --- /dev/null +++ b/ports/mimxrt/hal/phy/fsl_phy.h @@ -0,0 +1,258 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_PHY_H_ +#define _FSL_PHY_H_ + +#include "fsl_mdio.h" + +/*! @note The following PHY registers are the IEEE802.3 standard definition, same register and bit field may + have different names in various PHYs, but the feature they represent should be same or very similar. */ + +/*! @brief Defines the IEEE802.3 standard PHY registers. */ +#define PHY_BASICCONTROL_REG 0x00U /*!< The PHY basic control register. */ +#define PHY_BASICSTATUS_REG 0x01U /*!< The PHY basic status register. */ +#define PHY_ID1_REG 0x02U /*!< The PHY ID one register. */ +#define PHY_ID2_REG 0x03U /*!< The PHY ID two register. */ +#define PHY_AUTONEG_ADVERTISE_REG 0x04U /*!< The PHY auto-negotiate advertise register. */ +#define PHY_AUTONEG_LINKPARTNER_REG 0x05U /*!< The PHY auto negotiation link partner ability register. */ +#define PHY_AUTONEG_EXPANSION_REG 0x06U /*!< The PHY auto negotiation expansion register. */ +#define PHY_1000BASET_CONTROL_REG 0x09U /*!< The PHY 1000BASE-T control register. */ +#define PHY_MMD_ACCESS_CONTROL_REG 0x0DU /*!< The PHY MMD access control register. */ +#define PHY_MMD_ACCESS_DATA_REG 0x0EU /*!< The PHY MMD access data register. */ + +/*! @brief Defines the mask flag in basic control register(Address 0x00). */ +#define PHY_BCTL_SPEED1_MASK 0x0040U /*!< The PHY speed bit mask(MSB).*/ +#define PHY_BCTL_ISOLATE_MASK 0x0400U /*!< The PHY isolate mask.*/ +#define PHY_BCTL_DUPLEX_MASK 0x0100U /*!< The PHY duplex bit mask. */ +#define PHY_BCTL_RESTART_AUTONEG_MASK 0x0200U /*!< The PHY restart auto negotiation mask. */ +#define PHY_BCTL_AUTONEG_MASK 0x1000U /*!< The PHY auto negotiation bit mask. */ +#define PHY_BCTL_SPEED0_MASK 0x2000U /*!< The PHY speed bit mask(LSB). */ +#define PHY_BCTL_LOOP_MASK 0x4000U /*!< The PHY loop bit mask. */ +#define PHY_BCTL_RESET_MASK 0x8000U /*!< The PHY reset bit mask. */ + +/*! @brief Defines the mask flag in basic status register(Address 0x01). */ +#define PHY_BSTATUS_LINKSTATUS_MASK 0x0004U /*!< The PHY link status mask. */ +#define PHY_BSTATUS_AUTONEGABLE_MASK 0x0008U /*!< The PHY auto-negotiation ability mask. */ +#define PHY_BSTATUS_SPEEDUPLX_MASK 0x001CU /*!< The PHY speed and duplex mask. */ +#define PHY_BSTATUS_AUTONEGCOMP_MASK 0x0020U /*!< The PHY auto-negotiation complete mask. */ + +/*! @brief Defines the mask flag in PHY auto-negotiation advertise register(Address 0x04). */ +#define PHY_100BaseT4_ABILITY_MASK 0x200U /*!< The PHY have the T4 ability. */ +#define PHY_100BASETX_FULLDUPLEX_MASK 0x100U /*!< The PHY has the 100M full duplex ability.*/ +#define PHY_100BASETX_HALFDUPLEX_MASK 0x080U /*!< The PHY has the 100M full duplex ability.*/ +#define PHY_10BASETX_FULLDUPLEX_MASK 0x040U /*!< The PHY has the 10M full duplex ability.*/ +#define PHY_10BASETX_HALFDUPLEX_MASK 0x020U /*!< The PHY has the 10M full duplex ability.*/ +#define PHY_IEEE802_3_SELECTOR_MASK 0x001U /*!< The message type being sent by Auto-Nego.*/ + +/*! @brief Defines the mask flag in the 1000BASE-T control register(Address 0x09). */ +#define PHY_1000BASET_FULLDUPLEX_MASK 0x200U /*!< The PHY has the 1000M full duplex ability.*/ +#define PHY_1000BASET_HALFDUPLEX_MASK 0x100U /*!< The PHY has the 1000M half duplex ability.*/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +typedef struct _phy_handle phy_handle_t; +/*! @brief Defines the PHY link speed. */ +typedef enum _phy_speed +{ + kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */ + kPHY_Speed100M, /*!< ENET PHY 100M speed. */ + kPHY_Speed1000M /*!< ENET PHY 1000M speed. */ +} phy_speed_t; + +/*! @brief Defines the PHY link duplex. */ +typedef enum _phy_duplex +{ + kPHY_HalfDuplex = 0U, /*!< ENET PHY half duplex. */ + kPHY_FullDuplex /*!< ENET PHY full duplex. */ +} phy_duplex_t; + +/*! @brief Defines the PHY loopback mode. */ +typedef enum _phy_loop +{ + kPHY_LocalLoop = 0U, /*!< ENET PHY local/digital loopback. */ + kPHY_RemoteLoop, /*!< ENET PHY remote loopback. */ + kPHY_ExternalLoop, /*!< ENET PHY external loopback. */ +} phy_loop_t; + +/*! @brief Defines the PHY MMD data access mode. */ +typedef enum _phy_mmd_access_mode +{ + kPHY_MMDAccessNoPostIncrement = (1U << 14), /*!< ENET PHY MMD access data with no address post increment. */ + kPHY_MMDAccessRdWrPostIncrement = + (2U << 14), /*!< ENET PHY MMD access data with Read/Write address post increment. */ + kPHY_MMDAccessWrPostIncrement = (3U << 14), /*!< ENET PHY MMD access data with Write address post increment. */ +} phy_mmd_access_mode_t; + +/*! @brief Defines PHY configuration. */ +typedef struct _phy_config +{ + uint32_t phyAddr; /*!< PHY address. */ + phy_speed_t speed; /*!< PHY speed configuration. */ + phy_duplex_t duplex; /*!< PHY duplex configuration. */ + bool autoNeg; /*!< PHY auto-negotiation, true: enable, false: disable. */ + bool enableEEE; /*!< PHY Energy Efficient Ethernet. */ +} phy_config_t; + +/*! @brief PHY device operations. */ +typedef struct _phy_operations +{ + status_t (*phyInit)(phy_handle_t *handle, const phy_config_t *config); + status_t (*phyWrite)(phy_handle_t *handle, uint32_t phyReg, uint32_t data); + status_t (*phyRead)(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr); + status_t (*getAutoNegoStatus)(phy_handle_t *handle, bool *status); + status_t (*getLinkStatus)(phy_handle_t *handle, bool *status); + status_t (*getLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex); + status_t (*setLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex); + status_t (*enableLoopback)(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable); +} phy_operations_t; + +/*! @brief PHY device handle. */ + +struct _phy_handle +{ + uint32_t phyAddr; /*!< PHY address. */ + mdio_handle_t *mdioHandle; /*!< The MDIO handle used by the phy device, it is specified by device. */ + const phy_operations_t *ops; /*!< The device related operations. */ +}; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize PHY. + * + * @param handle PHY device handle. + * @param config Pointer to structure of phy_config_t. + * @retval kStatus_Success PHY initialization succeeds + * @retval kStatus_Fail PHY initialization fails + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_Init(phy_handle_t *handle, const phy_config_t *config) { + return handle->ops->phyInit(handle, config); +} +/*! + * @brief PHY Write function. This function write data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) { + return handle->ops->phyWrite(handle, phyReg, data); +} + +/*! + * @brief PHY Read function. This interface read data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) { + return handle->ops->phyRead(handle, phyReg, dataPtr); +} + +/*! + * @brief Gets the PHY auto-negotiation status. + * + * @param handle PHY device handle. + * @param status The auto-negotiation status of the PHY. + * - true the auto-negotiation is over. + * - false the auto-negotiation is on-going or not started. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) { + return handle->ops->getAutoNegoStatus(handle, status); +} + +/*! + * @brief Gets the PHY link status. + * + * @param handle PHY device handle. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY get link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_GetLinkStatus(phy_handle_t *handle, bool *status) { + return handle->ops->getLinkStatus(handle, status); +} + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @brief This function gets the speed and duplex mode of PHY. User can give one of speed + * and duplex address paramter and set the other as NULL if only wants to get one of them. + * + * @param handle PHY device handle. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY get link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) { + return handle->ops->getLinkSpeedDuplex(handle, speed, duplex); +} + +/*! + * @brief Sets the PHY link speed and duplex. + * + * @param handle PHY device handle. + * @param speed Specified PHY link speed. + * @param duplex Specified PHY link duplex. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) { + return handle->ops->setLinkSpeedDuplex(handle, speed, duplex); +} + +/*! + * @brief Enable PHY loopcback mode. + * + * @param handle PHY device handle. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * All loopback modes should not be set together, when one loopback mode is set + * another should be disabled. + * @param speed PHY speed for loopback mode. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY get link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) { + return handle->ops->enableLoopback(handle, mode, speed, enable); +} + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ +#endif diff --git a/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c new file mode 100644 index 000000000..8e679cd98 --- /dev/null +++ b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.c @@ -0,0 +1,128 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_enet_mdio.h" +#include "fsl_enet.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +static void ENET_MDIO_Init(mdio_handle_t *handle); +static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data); +static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr); + +uint32_t ENET_GetInstance(ENET_Type *base); +extern clock_ip_name_t s_enetClock[]; + +/******************************************************************************* + * Variables + ******************************************************************************/ + +const mdio_operations_t enet_ops = {.mdioInit = ENET_MDIO_Init, + .mdioWrite = ENET_MDIO_Write, + .mdioRead = ENET_MDIO_Read, + .mdioWriteExt = NULL, + .mdioReadExt = NULL}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void ENET_MDIO_Init(mdio_handle_t *handle) { + mdio_resource_t *resource = (mdio_resource_t *)&handle->resource; + ENET_Type *base = (ENET_Type *)resource->base; + uint32_t instance = ENET_GetInstance(base); + + #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Set SMI first. */ + (void)CLOCK_EnableClock(s_enetClock[instance]); + #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + ENET_SetSMI(base, resource->csrClock_Hz, false); +} + +static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data) { + mdio_resource_t *resource = (mdio_resource_t *)&handle->resource; + ENET_Type *base = (ENET_Type *)resource->base; + status_t result = kStatus_Success; + #ifdef MDIO_TIMEOUT_COUNT + uint32_t counter; + #endif + + /* Clear the SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI write command. */ + ENET_StartSMIWrite(base, phyAddr, devAddr, kENET_MiiWriteValidFrame, data); + + /* Wait for SMI complete. */ + #ifdef MDIO_TIMEOUT_COUNT + for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--) + { + if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) { + break; + } + } + /* Check for timeout. */ + if (0U == counter) { + result = kStatus_PHY_SMIVisitTimeout; + } + #else + while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) { + } + #endif + + /* Clear SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + return result; +} + +static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr) { + assert(dataPtr); + + mdio_resource_t *resource = (mdio_resource_t *)&handle->resource; + ENET_Type *base = (ENET_Type *)resource->base; + #ifdef MDIO_TIMEOUT_COUNT + uint32_t counter; + #endif + + /* Clear the SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI read command operation. */ + ENET_StartSMIRead(base, phyAddr, devAddr, kENET_MiiReadValidFrame); + + /* Wait for SMI complete. */ + #ifdef MDIO_TIMEOUT_COUNT + for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--) + { + if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) { + break; + } + } + /* Check for timeout. */ + if (0U == counter) { + return kStatus_PHY_SMIVisitTimeout; + } + #else + while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) { + } + #endif + + /* Get data from SMI register. */ + *dataPtr = ENET_ReadSMIData(base); + + /* Clear SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + return kStatus_Success; +} diff --git a/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h new file mode 100644 index 000000000..500985d8f --- /dev/null +++ b/ports/mimxrt/hal/phy/mdio/enet/fsl_enet_mdio.h @@ -0,0 +1,21 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_ENET_MDIO_H_ +#define _FSL_ENET_MDIO_H_ + +#include "fsl_enet.h" +#include "fsl_mdio.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief ENET MDIO operations structure. */ +extern const mdio_operations_t enet_ops; + +#endif diff --git a/ports/mimxrt/hal/pin_mux.h b/ports/mimxrt/hal/pin_mux.h new file mode 100644 index 000000000..81036b0a2 --- /dev/null +++ b/ports/mimxrt/hal/pin_mux.h @@ -0,0 +1 @@ +// Empty file, necessary for compilation with NXP MCU SDK diff --git a/ports/mimxrt/hal/pwm_backport.c b/ports/mimxrt/hal/pwm_backport.c new file mode 100644 index 000000000..cea664212 --- /dev/null +++ b/ports/mimxrt/hal/pwm_backport.c @@ -0,0 +1,180 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * + * Copyright (c) 2021 Robert Hammelrath + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +// These are a few functions taken from the NXP-Lib +// for PWM, for +// - dealing with an u16 duty cycle setting, +// - setting the pulse center position, and +// - factoring out pure duty cycle change. + +#include "py/runtime.h" +#include "hal/pwm_backport.h" + +void PWM_UpdatePwmDutycycle_u16( + PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, uint16_t dutyCycle, uint16_t Center_u16) { + assert((uint16_t)pwmSignal < 2U); + uint16_t pulseCnt = 0, pwmHighPulse = 0; + uint16_t center; + + // check and confine bounds for Center_u16 + if ((Center_u16 + dutyCycle / 2) >= PWM_FULL_SCALE) { + Center_u16 = PWM_FULL_SCALE - dutyCycle / 2 - 1; + } else if (Center_u16 < (dutyCycle / 2)) { + Center_u16 = dutyCycle / 2; + } + pulseCnt = base->SM[subModule].VAL1 + 1; + // Calculate pulse width and center position + pwmHighPulse = (pulseCnt * dutyCycle) / PWM_FULL_SCALE; + center = (pulseCnt * Center_u16) / PWM_FULL_SCALE; + + // Setup the PWM dutycycle of channel A or B + if (pwmSignal == kPWM_PwmA) { + base->SM[subModule].VAL2 = center - pwmHighPulse / 2; + base->SM[subModule].VAL3 = base->SM[subModule].VAL2 + pwmHighPulse; + } else { + base->SM[subModule].VAL4 = center - pwmHighPulse / 2; + base->SM[subModule].VAL5 = base->SM[subModule].VAL4 + pwmHighPulse; + } +} + +void PWM_SetupPwm_u16(PWM_Type *base, pwm_submodule_t subModule, pwm_signal_param_u16_t *chnlParams, + uint32_t pwmFreq_Hz, uint32_t srcClock_Hz, bool output_enable) { + + uint32_t pwmClock; + uint16_t pulseCnt = 0; + uint8_t polarityShift = 0, outputEnableShift = 0; + + // Divide the clock by the prescale value + pwmClock = (srcClock_Hz / (1U << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT))); + pulseCnt = pwmClock / pwmFreq_Hz; + base->SM[subModule].INIT = 0; + base->SM[subModule].VAL1 = pulseCnt - 1; + + // Set up the Registers VAL2..VAL5 controlling the duty cycle of channel A/B + PWM_UpdatePwmDutycycle_u16(base, subModule, chnlParams->pwmChannel, + chnlParams->dutyCycle_u16, chnlParams->Center_u16); + + // Setup register shift values based on the channel being configured. + // Also setup the deadtime value + if (chnlParams->pwmChannel == kPWM_PwmA) { + polarityShift = PWM_OCTRL_POLA_SHIFT; + outputEnableShift = PWM_OUTEN_PWMA_EN_SHIFT; + base->SM[subModule].DTCNT0 = PWM_DTCNT0_DTCNT0(chnlParams->deadtimeValue); + } else { + polarityShift = PWM_OCTRL_POLB_SHIFT; + outputEnableShift = PWM_OUTEN_PWMB_EN_SHIFT; + base->SM[subModule].DTCNT1 = PWM_DTCNT1_DTCNT1(chnlParams->deadtimeValue); + } + + // Setup signal active level + if (chnlParams->level == kPWM_HighTrue) { + base->SM[subModule].OCTRL &= ~(1U << polarityShift); + } else { + base->SM[subModule].OCTRL |= (1U << polarityShift); + } + // Enable PWM output + if (output_enable) { + base->OUTEN |= (1U << (outputEnableShift + subModule)); + } +} + +void PWM_SetupPwmx_u16(PWM_Type *base, pwm_submodule_t subModule, + uint32_t pwmFreq_Hz, uint16_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz) { + + uint32_t pulseCnt; + uint32_t pwmClock; + + // Divide the clock by the prescale value + pwmClock = (srcClock_Hz / (1U << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT))); + pulseCnt = pwmClock / pwmFreq_Hz; + base->SM[subModule].INIT = 0; + base->SM[subModule].VAL0 = ((uint32_t)duty_cycle * pulseCnt) / PWM_FULL_SCALE; + base->SM[subModule].VAL1 = pulseCnt - 1; + + base->SM[subModule].OCTRL = (base->SM[subModule].OCTRL & ~PWM_OCTRL_POLX_MASK) | PWM_OCTRL_POLX(!invert); + + base->OUTEN |= (1U << subModule); +} + +void PWM_SetupFaultDisableMap(PWM_Type *base, pwm_submodule_t subModule, + pwm_channels_t pwmChannel, pwm_fault_channels_t pwm_fault_channels, uint16_t value) { + uint16_t reg = base->SM[subModule].DISMAP[pwm_fault_channels]; + switch (pwmChannel) { + case kPWM_PwmA: + reg &= ~((uint16_t)PWM_DISMAP_DIS0A_MASK); + reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0A_SHIFT) & (uint16_t)PWM_DISMAP_DIS0A_MASK); + break; + case kPWM_PwmB: + reg &= ~((uint16_t)PWM_DISMAP_DIS0B_MASK); + reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0B_SHIFT) & (uint16_t)PWM_DISMAP_DIS0B_MASK); + break; + case kPWM_PwmX: + reg &= ~((uint16_t)PWM_DISMAP_DIS0X_MASK); + reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0X_SHIFT) & (uint16_t)PWM_DISMAP_DIS0X_MASK); + break; + default: + assert(false); + break; + } + base->SM[subModule].DISMAP[pwm_fault_channels] = reg; +} + +#ifdef FSL_FEATURE_SOC_TMR_COUNT +status_t QTMR_SetupPwm_u16(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t pwmFreqHz, + uint16_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init) { + uint32_t periodCount, highCount, lowCount, reg; + + if (dutyCycleU16 >= PWM_FULL_SCALE) { + // Invalid dutycycle + return kStatus_Fail; + } + + // Counter values to generate a PWM signal + periodCount = (srcClock_Hz / pwmFreqHz) - 1; + highCount = (periodCount * dutyCycleU16) / PWM_FULL_SCALE; + lowCount = periodCount - highCount; + + // Setup the compare registers for PWM output + if (is_init == false) { + base->CHANNEL[channel].COMP1 = lowCount; + base->CHANNEL[channel].COMP2 = highCount; + } + + // Setup the pre-load registers for PWM output + base->CHANNEL[channel].CMPLD1 = lowCount; + base->CHANNEL[channel].CMPLD2 = highCount; + + reg = base->CHANNEL[channel].CSCTRL; + // Setup the compare load control for COMP1 and COMP2. + // Load COMP1 when CSCTRL[TCF2] is asserted, load COMP2 when CSCTRL[TCF1] is asserted + reg &= ~(TMR_CSCTRL_CL1_MASK | TMR_CSCTRL_CL2_MASK); + reg |= (TMR_CSCTRL_CL1(kQTMR_LoadOnComp2) | TMR_CSCTRL_CL2(kQTMR_LoadOnComp1)); + base->CHANNEL[channel].CSCTRL = reg; + + // Set OFLAG pin for output mode + base->CHANNEL[channel].SCTRL |= TMR_SCTRL_OEN_MASK; + if (outputPolarity) { + // Invert the polarity + base->CHANNEL[channel].SCTRL |= TMR_SCTRL_OPS_MASK; + } else { + // True polarity, no inversion + base->CHANNEL[channel].SCTRL &= ~TMR_SCTRL_OPS_MASK; + } + + reg = base->CHANNEL[channel].CTRL; + reg &= ~(TMR_CTRL_OUTMODE_MASK); + // Count until compare value is reached and re-initialize the counter, toggle OFLAG output + // using alternating compare register + reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg)); + base->CHANNEL[channel].CTRL = reg; + + return kStatus_Success; +} +#endif // FSL_FEATURE_SOC_TMR_COUNT diff --git a/ports/mimxrt/hal/pwm_backport.h b/ports/mimxrt/hal/pwm_backport.h new file mode 100644 index 000000000..cd4bdb1f8 --- /dev/null +++ b/ports/mimxrt/hal/pwm_backport.h @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * + * Copyright (c) 2021 Robert Hammelrath + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef PWM_BACKPORT_H +#define PWM_BACKPORT_H +#include "fsl_pwm.h" +#ifdef FSL_FEATURE_SOC_TMR_COUNT +#include "fsl_qtmr.h" +#endif + +typedef struct _pwm_signal_param_u16 +{ + pwm_channels_t pwmChannel; // PWM channel being configured; PWM A or PWM B + uint16_t dutyCycle_u16; // PWM pulse width, value should be between 0 to 65536 + uint16_t Center_u16; // Center of the pulse, value should be between 0 to 65536 + pwm_level_select_t level; // PWM output active level select */ + uint16_t deadtimeValue; // The deadtime value; only used if channel pair is operating in complementary mode +} pwm_signal_param_u16_t; + +typedef enum _pwm_fault_channels { + kPWM_faultchannel_0 = 0U, + kPWM_faultchannel_1 +} pwm_fault_channels_t; + +#define PWM_FULL_SCALE (65536UL) + +void PWM_UpdatePwmDutycycle_u16(PWM_Type *base, pwm_submodule_t subModule, + pwm_channels_t pwmSignal, uint16_t dutyCycle, uint16_t center); + +void PWM_SetupPwm_u16(PWM_Type *base, pwm_submodule_t subModule, pwm_signal_param_u16_t *chnlParams, + uint32_t pwmFreq_Hz, uint32_t srcClock_Hz, bool output_enable); + +void PWM_SetupPwmx_u16(PWM_Type *base, pwm_submodule_t subModule, + uint32_t pwmFreq_Hz, uint16_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz); + +void PWM_SetupFaultDisableMap(PWM_Type *base, pwm_submodule_t subModule, + pwm_channels_t pwmChannel, pwm_fault_channels_t pwm_fault_channels, uint16_t value); + +#ifdef FSL_FEATURE_SOC_TMR_COUNT +status_t QTMR_SetupPwm_u16(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t pwmFreqHz, + uint16_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init); +#endif // FSL_FEATURE_SOC_TMR_COUNT + +#endif // PWM_BACKPORT_H diff --git a/ports/mimxrt/hal/qspi_hyper_flash_config.c b/ports/mimxrt/hal/qspi_hyper_flash_config.c new file mode 100644 index 000000000..17a952b68 --- /dev/null +++ b/ports/mimxrt/hal/qspi_hyper_flash_config.c @@ -0,0 +1,186 @@ +/* + * Copyright 2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "flexspi_flash_config.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.xip_board" +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ +#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__) +__attribute__((section(".boot_hdr.conf"))) +#elif defined(__ICCARM__) +#pragma location = ".boot_hdr.conf" +#endif + +const flexspi_nor_config_t qspiflash_config = { + .memConfig = + { + .tag = FLEXSPI_CFG_BLK_TAG, + .version = FLEXSPI_CFG_BLK_VERSION, + .readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad, + .csHoldTime = 3u, + .csSetupTime = 3u, + .columnAddressWidth = 3u, + // Enable DDR mode, Wordaddressable, Safe configuration, Differential clock + .controllerMiscOption = + (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << kFlexSpiMiscOffset_WordAddressableEnable) | + (1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DiffClkEnable), + .sflashPadType = kSerialFlash_8Pads, + .serialClkFreq = kFlexSpiSerialClk_133MHz, + .sflashA1Size = MICROPY_HW_FLASH_SIZE, + .dataValidTime = {16u, 16u}, + .lookupTable = + { + /* 0 Read Data */ + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04), + + /* 1 Write Data */ + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x02), + + /* 2 Read Status */ + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 2] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 3] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x70), // DATA 0x70 + // +1 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 4] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 5] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x0B), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_READSTATUS + 6] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), + + /* 4 Write Enable */ + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 2] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 3] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // DATA 0xAA + // +1 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 4] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 5] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 6] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEENABLE + 7] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), + + /* 6 Erase Sector */ + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 2] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 3] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), // DATA 0x80 + // +1 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 4] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 5] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 6] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 7] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 + // +2 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 8] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 9] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 10] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 11] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), + // +3 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 12] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 13] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASESECTOR + 14] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x30, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), + + /* 10 program page with word program command sequence */ + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), // ADDR 0x555 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 2] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 3] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0), // DATA 0xA0 + // +1 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 4] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 5] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x80), + + /* 12 Erase chip */ + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 1] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 2] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 3] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x80), + // +1 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 4] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 5] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 6] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 7] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), + // +2 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 8] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 9] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 10] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x02), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 11] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x55), + // +3 + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 12] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 13] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xAA), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 14] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x05), + [4 * HYPERFLASH_CMD_LUT_SEQ_IDX_ERASECHIP + 15] = + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x00, kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x10), + }, + }, + .pageSize = 512u, + .sectorSize = 256u * 1024u, + .blockSize = 256u * 1024u, + .isUniformBlockSize = true, +}; + +#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/hal/qspi_nor_flash_config.c b/ports/mimxrt/hal/qspi_nor_flash_config.c new file mode 100644 index 000000000..f42730ad5 --- /dev/null +++ b/ports/mimxrt/hal/qspi_nor_flash_config.c @@ -0,0 +1,140 @@ +/* + * Copyright 2019 NXP. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +// Based on tinyusb/hw/bsp/teensy_40/evkmimxrt1010_flexspi_nor_config.c + +#include "flexspi_flash_config.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.xip_board" +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ +#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1) +#if defined(__ARMCC_VERSION) || defined(__GNUC__) +__attribute__((section(".boot_hdr.conf"))) +#elif defined(__ICCARM__) +#pragma location = ".boot_hdr.conf" +#endif + +#ifndef MICROPY_HW_FLASH_DQS +#define MICROPY_HW_FLASH_DQS kFlexSPIReadSampleClk_LoopbackFromDqsPad +#endif + +const flexspi_nor_config_t qspiflash_config = { + .memConfig = + { + .tag = FLEXSPI_CFG_BLK_TAG, + .version = FLEXSPI_CFG_BLK_VERSION, + .readSampleClkSrc = MICROPY_HW_FLASH_DQS, + .csHoldTime = 3u, + .csSetupTime = 3u, + .busyOffset = FLASH_BUSY_STATUS_OFFSET, // Status bit 0 indicates busy. + .busyBitPolarity = FLASH_BUSY_STATUS_POL, // Busy when the bit is 1. + .deviceModeCfgEnable = 1u, + .deviceModeType = kDeviceConfigCmdType_QuadEnable, + .deviceModeSeq = { + .seqId = 4u, + .seqNum = 1u, + }, + .deviceModeArg = 0x40, + // Enable DDR mode, Wordaddassable, Safe configuration, Differential clock + .deviceType = kFlexSpiDeviceType_SerialNOR, + .sflashPadType = kSerialFlash_4Pads, + .serialClkFreq = kFlexSpiSerialClk_100MHz, + .sflashA1Size = MICROPY_HW_FLASH_SIZE, + .lookupTable = + { + // 0 Read LUTs 0 -> 0 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), + FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 1 Read status register -> 1 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x01), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 2 Fast read quad mode - SDR + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x6B, RADDR_SDR, FLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x08, READ_SDR, FLEXSPI_4PAD, 0x04), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 3 Write Enable -> 3 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 4 Read extend parameters + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, READ_SDR, FLEXSPI_1PAD, 0x04), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 5 Erase Sector -> 5 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 6 Write Status Reg + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x04), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 7 Page Program - quad mode (-> 9) + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x32, RADDR_SDR, FLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 8 Read ID + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x90, DUMMY_SDR, FLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x00, 0, 0, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 9 Page Program - single mode -> 9 + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0, 0, 0, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 10 Enter QPI mode + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x35, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 11 Erase Chip + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + + // 12 Exit QPI mode + FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xF5, STOP, FLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler + }, + }, + .pageSize = 256u, + .sectorSize = 4u * 1024u, + .blockSize = 64u * 1024u, + .isUniformBlockSize = false, + // .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz, +}; +#endif /* XIP_BOOT_HEADER_ENABLE */ diff --git a/ports/mimxrt/hal/resethandler_MIMXRT10xx.S b/ports/mimxrt/hal/resethandler_MIMXRT10xx.S new file mode 100644 index 000000000..8fe061103 --- /dev/null +++ b/ports/mimxrt/hal/resethandler_MIMXRT10xx.S @@ -0,0 +1,175 @@ +/* ------------------------------------------------------------------------- */ +/* */ +/* Copyright 1997-2016 Freescale Semiconductor, Inc. */ +/* Copyright 2016-2019 NXP */ +/* All rights reserved. */ +/* */ +/* SPDX-License-Identifier: BSD-3-Clause */ +/*****************************************************************************/ +/* Version: GCC for ARM Embedded Processors */ +/*****************************************************************************/ + .syntax unified + .arch armv7-m + +#include"flexram_config.s" + + +/* Reset Handler */ + + .thumb_func + .align 2 + .globl Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + cpsid i /* Mask interrupts */ + .equ VTOR, 0xE000ED08 + ldr r0, =VTOR + ldr r1, =__isr_vector + str r1, [r0] + ldr r2, [r1] + msr msp, r2 + +/* Reconfigure the memory map, which must match the setting of the linker script */ + dsb + isb + ldr r0, =__iomux_gpr17_adr /* load IOMUXC_GPR17 register address to R0 */ + ldr r1, =__iomux_gpr17_value /* move FlexRAM configuration value to R1 */ + str r1,[r0] /* store FLEXRAM configuration value to IOMUXC_GPR17 */ + dsb + isb + ldr r0, =__iomux_gpr16_adr /* load IOMUXC_GPR16 register address to R0 */ + ldr r1,[r0] /* load IOMUXC_GPR16 register value to R1 */ + orr r1, r1, #4 /* set corresponding FLEXRAM_BANK_CFG_SEL bit */ + str r1,[r0] /* store the value to IOMUXC_GPR16 (FLEXRAM_BANK_CFG_SEL = '1') */ + dsb + isb + +#ifndef __NO_SYSTEM_INIT + ldr r0,=SystemInit + blx r0 +#endif +/* Loop to copy data from read only memory to RAM. The ranges + * of copy from/to are specified by following symbols evaluated in + * linker script. + * __etext: End of code section, i.e., begin of data sections to copy from. + * __data_start__/__data_end__: RAM address range that data should be + * __noncachedata_start__/__noncachedata_end__ : none cachable region + * __ram_function_start__/__ram_function_end__ : ramfunction region + * copied to. Both must be aligned to 4 bytes boundary. */ + + ldr r1, =__etext + ldr r2, =__data_start__ + ldr r3, =__data_end__ + +#ifdef __PERFORMANCE_IMPLEMENTATION +/* Here are two copies of loop implementations. First one favors performance + * and the second one favors code size. Default uses the second one. + * Define macro "__PERFORMANCE_IMPLEMENTATION" in project to use the first one */ + subs r3, r2 + ble .LC1 +.LC0: + subs r3, #4 + ldr r0, [r1, r3] + str r0, [r2, r3] + bgt .LC0 +.LC1: +#else /* code size implemenation */ +.LC0: + cmp r2, r3 + ittt lt + ldrlt r0, [r1], #4 + strlt r0, [r2], #4 + blt .LC0 +#endif +#ifdef __STARTUP_INITIALIZE_RAMFUNCTION + ldr r2, =__ram_function_start__ + ldr r3, =__ram_function_end__ +#ifdef __PERFORMANCE_IMPLEMENTATION +/* Here are two copies of loop implementations. First one favors performance + * and the second one favors code size. Default uses the second one. + * Define macro "__PERFORMANCE_IMPLEMENTATION" in project to use the first one */ + subs r3, r2 + ble .LC_ramfunc_copy_end +.LC_ramfunc_copy_start: + subs r3, #4 + ldr r0, [r1, r3] + str r0, [r2, r3] + bgt .LC_ramfunc_copy_start +.LC_ramfunc_copy_end: +#else /* code size implemenation */ +.LC_ramfunc_copy_start: + cmp r2, r3 + ittt lt + ldrlt r0, [r1], #4 + strlt r0, [r2], #4 + blt .LC_ramfunc_copy_start +#endif +#endif /* __STARTUP_INITIALIZE_RAMFUNCTION */ +#ifdef __STARTUP_INITIALIZE_NONCACHEDATA + ldr r2, =__noncachedata_start__ + ldr r3, =__noncachedata_init_end__ +#ifdef __PERFORMANCE_IMPLEMENTATION +/* Here are two copies of loop implementations. First one favors performance + * and the second one favors code size. Default uses the second one. + * Define macro "__PERFORMANCE_IMPLEMENTATION" in project to use the first one */ + subs r3, r2 + ble .LC3 +.LC2: + subs r3, #4 + ldr r0, [r1, r3] + str r0, [r2, r3] + bgt .LC2 +.LC3: +#else /* code size implemenation */ +.LC2: + cmp r2, r3 + ittt lt + ldrlt r0, [r1], #4 + strlt r0, [r2], #4 + blt .LC2 +#endif +/* zero inited ncache section initialization */ + ldr r3, =__noncachedata_end__ + movs r0,0 +.LC4: + cmp r2,r3 + itt lt + strlt r0,[r2],#4 + blt .LC4 +#endif /* __STARTUP_INITIALIZE_NONCACHEDATA */ + +#ifdef __STARTUP_CLEAR_BSS +/* This part of work usually is done in C library startup code. Otherwise, + * define this macro to enable it in this startup. + * + * Loop to zero out BSS section, which uses following symbols + * in linker script: + * __bss_start__: start of BSS section. Must align to 4 + * __bss_end__: end of BSS section. Must align to 4 + */ + ldr r1, =__bss_start__ + ldr r2, =__bss_end__ + + movs r0, 0 +.LC5: + cmp r1, r2 + itt lt + strlt r0, [r1], #4 + blt .LC5 +#endif /* __STARTUP_CLEAR_BSS */ + + cpsie i /* Unmask interrupts */ +#ifndef __START +#define __START _start +#endif +#ifndef __ATOLLIC__ + ldr r0,=__START + blx r0 +#else + ldr r0,=__libc_init_array + blx r0 + ldr r0,=main + bx r0 +#endif + .pool + .size Reset_Handler, . - Reset_Handler diff --git a/ports/mimxrt/lwip_inc/arch/cc.h b/ports/mimxrt/lwip_inc/arch/cc.h new file mode 100644 index 000000000..c37e62b83 --- /dev/null +++ b/ports/mimxrt/lwip_inc/arch/cc.h @@ -0,0 +1,10 @@ +#ifndef MICROPY_INCLUDED_MIMXRT_LWIP_ARCH_CC_H +#define MICROPY_INCLUDED_MIMXRT_LWIP_ARCH_CC_H + +#include +#define LWIP_PLATFORM_DIAG(x) +#define LWIP_PLATFORM_ASSERT(x) { assert(1); } + +#define LWIP_NO_CTYPE_H 1 + +#endif // MICROPY_INCLUDED_MIMXRT_LWIP_ARCH_CC_H diff --git a/ports/mimxrt/lwip_inc/arch/sys_arch.h b/ports/mimxrt/lwip_inc/arch/sys_arch.h new file mode 100644 index 000000000..8b1a39374 --- /dev/null +++ b/ports/mimxrt/lwip_inc/arch/sys_arch.h @@ -0,0 +1 @@ +// empty diff --git a/ports/mimxrt/lwip_inc/lwipopts.h b/ports/mimxrt/lwip_inc/lwipopts.h new file mode 100644 index 000000000..2401c05f9 --- /dev/null +++ b/ports/mimxrt/lwip_inc/lwipopts.h @@ -0,0 +1,56 @@ +#ifndef MICROPY_INCLUDED_MIMXRT_LWIP_LWIPOPTS_H +#define MICROPY_INCLUDED_MIMXRT_LWIP_LWIPOPTS_H + +#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 + +#define LWIP_CHKSUM_ALGORITHM 3 +// The checksum flags are set in eth.c +#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 + +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_RAW 1 +#define LWIP_NETCONN 0 +#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 +#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 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 + +extern uint32_t trng_random_u32(void); +#define LWIP_RAND() trng_random_u32() + +// lwip takes 26700 bytes +#define MEM_SIZE (8000) +#define TCP_MSS (800) +#define TCP_WND (8 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define MEMP_NUM_TCP_SEG (32) + +typedef uint32_t sys_prot_t; + +#endif // MICROPY_INCLUDED_MIMXRT_LWIP_LWIPOPTS_H diff --git a/ports/mimxrt/machine_bitstream.c b/ports/mimxrt/machine_bitstream.c new file mode 100644 index 000000000..cb391a38c --- /dev/null +++ b/ports/mimxrt/machine_bitstream.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +// This is a translation of the cycle counter implementation in ports/stm32/machine_bitstream.c. + +#include "py/mpconfig.h" +#include "py/mphal.h" + +#if MICROPY_PY_MACHINE_BITSTREAM + +#define NS_TICKS_OVERHEAD (6) + +void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) __attribute__((section(".ram_functions"))); +void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) { + uint32_t fcpu_mhz = mp_hal_get_cpu_freq() / 1000000; + // Convert ns to us ticks [high_time_0, period_0, high_time_1, period_1]. + for (size_t i = 0; i < 4; ++i) { + timing_ns[i] = fcpu_mhz * timing_ns[i] / 1000; + if (timing_ns[i] > NS_TICKS_OVERHEAD) { + timing_ns[i] -= NS_TICKS_OVERHEAD; + } + if (i % 2 == 1) { + // Convert low_time to period (i.e. add high_time). + timing_ns[i] += timing_ns[i - 1]; + } + } + // Enable the CPU cycle counter, which is not always enabled. + mp_hal_ticks_cpu_enable(); + + uint32_t irq_state = mp_hal_quiet_timing_enter(); + + for (size_t i = 0; i < len; ++i) { + uint8_t b = buf[i]; + for (size_t j = 0; j < 8; ++j) { + uint32_t start_ticks = mp_hal_ticks_cpu(); + mp_hal_pin_high(pin); + uint32_t *t = &timing_ns[b >> 6 & 2]; + while ((mp_hal_ticks_cpu() - start_ticks) < t[0]) { + } + mp_hal_pin_low(pin); + b <<= 1; + while ((mp_hal_ticks_cpu() - start_ticks) < t[1]) { + } + } + } + + mp_hal_quiet_timing_exit(irq_state); +} + +#endif // MICROPY_PY_MACHINE_BITSTREAM diff --git a/ports/mimxrt/machine_pwm.c b/ports/mimxrt/machine_pwm.c new file mode 100644 index 000000000..a13af0d80 --- /dev/null +++ b/ports/mimxrt/machine_pwm.c @@ -0,0 +1,618 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Damien P. George + * Copyright (c) 2021 Robert Hammelrath + * + * 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 "modmachine.h" +#include "pin.h" +#include "fsl_clock.h" +#include "fsl_iomuxc.h" +#include "hal/pwm_backport.h" + +#define PWM_MIDDLE (0) +#define PWM_BEGIN (1) +#define PWM_END (2) + +#define PWM_CHANNEL1 (1) +#define PWM_CHANNEL2 (2) + +typedef struct _machine_pwm_obj_t { + mp_obj_base_t base; + PWM_Type *instance; + bool is_flexpwm; + uint8_t complementary; + uint8_t module; + uint8_t submodule; + uint8_t channel1; + uint8_t channel2; + uint8_t invert; + bool sync; + uint32_t freq; + int16_t prescale; + uint16_t duty_u16; + uint32_t duty_ns; + uint16_t center; + uint32_t deadtime; + bool output_enable_1; + bool output_enable_2; + uint8_t xor; + bool is_init; +} machine_pwm_obj_t; + +static char channel_char[] = {'B', 'A', 'X' }; +static char *ERRMSG_FREQ = "PWM frequency too low"; +static char *ERRMSG_INIT = "PWM set-up failed"; +static char *ERRMSG_VALUE = "value larger than period"; + +STATIC void machine_pwm_start(machine_pwm_obj_t *self); + +STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->is_flexpwm) { + mp_printf(print, "module, self->submodule); + if (self->complementary) { + mp_printf(print, "channel=%c/%c", channel_char[self->channel1], channel_char[self->channel2]); + } else { + mp_printf(print, "channel=%c", channel_char[self->channel1]); + } + if (self->duty_ns != 0) { + mp_printf(print, " duty_ns=%u", self->duty_ns); + } else { + mp_printf(print, " duty_u16=%u", self->duty_u16); + } + mp_printf(print, " freq=%u center=%u, deadtime=%u, sync=%u>", + self->freq, self->center, self->deadtime, self->sync); + #ifdef FSL_FEATURE_SOC_TMR_COUNT + } else { + mp_printf(print, "module, self->channel1, self->freq); + if (self->duty_ns != 0) { + mp_printf(print, "duty_ns=%u>", self->duty_ns); + } else { + mp_printf(print, "duty_u16=%u>", self->duty_u16); + } + #endif + } +} + +// Utility functions for decoding and convertings +// +STATIC uint32_t duty_ns_to_duty_u16(uint32_t freq, uint32_t duty_ns) { + uint64_t duty = (uint64_t)duty_ns * freq * PWM_FULL_SCALE / 1000000000ULL; + if (duty >= PWM_FULL_SCALE) { + mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE)); + } + return (uint32_t)duty; +} + +STATIC uint8_t module_decode(char channel) { + switch (channel) { + case '0': + return kPWM_Module_0; + case '1': + return kPWM_Module_1; + case '2': + return kPWM_Module_2; + case '3': + return kPWM_Module_3; + default: + return kPWM_Module_1; + } +} + +STATIC uint8_t channel_decode(char channel) { + switch (channel) { + case 'A': + return kPWM_PwmA; + case 'B': + return kPWM_PwmB; + case 'X': + return kPWM_PwmX; + default: + return kPWM_PwmA; + } +} + +// decode the AF objects module and Port numer. Returns NULL if it is not a FLEXPWM object +STATIC const machine_pin_af_obj_t *af_name_decode_flexpwm(const machine_pin_af_obj_t *af_obj, + uint8_t *module, uint8_t *submodule, uint8_t *channel) { + const char *str; + size_t len; + str = (char *)qstr_data(af_obj->name, &len); + // test for the name starting with FLEXPWM + if (len < 15 || strncmp(str, "FLEXPWM", 7) != 0) { + return NULL; + } + // Get module, submodule and channel from the name, e.g. FLEXPWM1_PWM0_A + *module = str[7] - '0'; + *submodule = module_decode(str[12]); + *channel = channel_decode(str[14]); + + return af_obj; +} + +#ifdef FSL_FEATURE_SOC_TMR_COUNT +STATIC uint8_t qtmr_decode(char channel) { + switch (channel) { + case '0': + return kQTMR_Channel_0; + case '1': + return kQTMR_Channel_1; + case '2': + return kQTMR_Channel_2; + case '3': + return kQTMR_Channel_3; + default: + return kPWM_Module_1; + } +} + +// decode the AF objects module and Port numer. Returns NULL if it is not a QTMR object +STATIC const machine_pin_af_obj_t *af_name_decode_qtmr(const machine_pin_af_obj_t *af_obj, uint8_t *module, uint8_t *channel) { + const char *str; + size_t len; + str = (char *)qstr_data(af_obj->name, &len); + // test for the name starting with TMR + if (len < 11 || strncmp(str, "TMR", 3) != 0) { + return NULL; + } + // Get module, submodule and channel from the name, e.g. FLEXPWM1_PWM0_A + *module = str[3] - '0'; + *channel = qtmr_decode(str[10]); + + return af_obj; +} +#endif + +STATIC bool is_board_pin(const machine_pin_obj_t *pin) { + for (int i = 0; i < num_board_pins; i++) { + if (pin == machine_pin_board_pins[i]) { + return true; + } + } + return false; +} + +// Functions for configuring the PWM Device +// +STATIC int calc_prescaler(uint32_t clock, uint32_t freq) { + float temp = (float)clock / (float)PWM_FULL_SCALE / (float)freq; + for (int prescale = 0; prescale < 8; prescale++, temp /= 2) { + if (temp <= 1) { + return prescale; + } + } + // Frequency too low, cannot scale down. + return -1; +} + +STATIC void configure_flexpwm(machine_pwm_obj_t *self) { + pwm_signal_param_u16_t pwmSignal; + + // Initialize PWM module. + uint32_t pwmSourceClockInHz = CLOCK_GetFreq(kCLOCK_IpgClk); + + int prescale = calc_prescaler(pwmSourceClockInHz, self->freq); + if (prescale < 0) { + mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_FREQ)); + } + if (self->prescale != prescale || self->is_init == false) { + pwm_config_t pwmConfig; + PWM_GetDefaultConfig(&pwmConfig); + self->prescale = prescale; + pwmConfig.prescale = prescale; + pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; + if (self->complementary) { + pwmConfig.pairOperation = self->channel1 == kPWM_PwmA ? kPWM_ComplementaryPwmA : kPWM_ComplementaryPwmB; + } else { + pwmConfig.pairOperation = kPWM_Independent; + } + pwmConfig.clockSource = kPWM_BusClock; + pwmConfig.enableWait = false; + pwmConfig.initializationControl = self->sync ? kPWM_Initialize_MasterSync : kPWM_Initialize_LocalSync; + + if (PWM_Init(self->instance, self->submodule, &pwmConfig) == kStatus_Fail) { + mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_INIT)); + } + } + + // Disable the fault detect function to avoid using the xbara + PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel1, kPWM_faultchannel_0, 0); + PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel1, kPWM_faultchannel_1, 0); + if (self->complementary) { + PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel2, kPWM_faultchannel_0, 0); + PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel2, kPWM_faultchannel_1, 0); + } + + if (self->channel1 != kPWM_PwmX) { // Only for A/B channels + // Initialize the channel parameters + pwmSignal.pwmChannel = self->channel1; + pwmSignal.level = (self->invert & PWM_CHANNEL1) ? kPWM_LowTrue : kPWM_HighTrue; + pwmSignal.dutyCycle_u16 = self->duty_u16; + pwmSignal.Center_u16 = self->center; + pwmSignal.deadtimeValue = ((uint64_t)pwmSourceClockInHz * self->deadtime) / 1000000000ULL; + PWM_SetupPwm_u16(self->instance, self->submodule, &pwmSignal, self->freq, + pwmSourceClockInHz, self->output_enable_1); + + if (self->complementary) { + // Initialize the second channel of the pair. + pwmSignal.pwmChannel = self->channel2; + pwmSignal.level = (self->invert & PWM_CHANNEL2) ? kPWM_LowTrue : kPWM_HighTrue; + PWM_SetupPwm_u16(self->instance, self->submodule, &pwmSignal, self->freq, + pwmSourceClockInHz, self->output_enable_2); + } + if (self->xor == 1) { + // Set the DBLEN bit for A, B = A ^ B + self->instance->SM[self->submodule].CTRL &= ~PWM_CTRL_SPLIT_MASK; + self->instance->SM[self->submodule].CTRL |= PWM_CTRL_DBLEN_MASK; + } else if (self->xor == 2) { + // Set the DBLEN and SPLIT bits for A, B = A ^ B + self->instance->SM[self->submodule].CTRL |= PWM_CTRL_DBLEN_MASK | PWM_CTRL_SPLIT_MASK; + } else { + self->instance->SM[self->submodule].CTRL &= ~(PWM_CTRL_DBLEN_MASK | PWM_CTRL_SPLIT_MASK); + } + } else { + PWM_SetupPwmx_u16(self->instance, self->submodule, self->freq, self->duty_u16, + self->invert, pwmSourceClockInHz); + if (self->xor) { + // Set the DBLX bit for X = A ^ B + self->instance->SM[self->submodule].CTRL |= PWM_CTRL_DBLX_MASK; + } else { + self->instance->SM[self->submodule].CTRL &= ~PWM_CTRL_DBLX_MASK; + } + } + // Set the load okay bit for the submodules + PWM_SetPwmLdok(self->instance, 1 << self->submodule, true); + + // Start the PWM generation from the Submodules + PWM_StartTimer(self->instance, 1 << self->submodule); +} + +#ifdef FSL_FEATURE_SOC_TMR_COUNT +STATIC void configure_qtmr(machine_pwm_obj_t *self) { + qtmr_config_t qtmrConfig; + int prescale; + + TMR_Type *instance = (TMR_Type *)self->instance; + + prescale = calc_prescaler(CLOCK_GetFreq(kCLOCK_IpgClk), self->freq); + if (prescale < 0) { + mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_FREQ)); + } + if (prescale != self->prescale) { + QTMR_GetDefaultConfig(&qtmrConfig); + qtmrConfig.primarySource = prescale + kQTMR_ClockDivide_1; + QTMR_Init(instance, self->channel1, &qtmrConfig); + self->prescale = prescale; + } + // Set up the PWM channel + if (QTMR_SetupPwm_u16(instance, self->channel1, self->freq, self->duty_u16, + self->invert, CLOCK_GetFreq(kCLOCK_IpgClk) / (1 << prescale), self->is_init) == kStatus_Fail) { + mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_INIT)); + } + // Start the output + QTMR_StartTimer(instance, self->channel1, kQTMR_PriSrcRiseEdge); +} +#endif // FSL_FEATURE_SOC_TMR_COUNT + +STATIC void configure_pwm(machine_pwm_obj_t *self) { + // Set the clock frequencies + // Freq range is 15Hz to ~ 3 MHz. + static bool set_frequency = true; + // set the frequency only once + if (set_frequency) { + CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); // Set IPG PODF to 3, divide by 4 + set_frequency = false; + } + + if (self->duty_ns != 0) { + self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns); + } + if (self->is_flexpwm) { + configure_flexpwm(self); + #ifdef FSL_FEATURE_SOC_TMR_COUNT + } else { + configure_qtmr(self); + #endif + } +} + +// Micropython API functions +// +STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, + size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_freq, ARG_duty_u16, ARG_duty_ns, ARG_center, ARG_align, + ARG_invert, ARG_sync, ARG_xor, ARG_deadtime }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_duty_u16, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_duty_ns, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_center, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_align, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, + { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, + { MP_QSTR_sync, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, + { MP_QSTR_xor, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}}, + { MP_QSTR_deadtime, 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); + + if ((n_args + kw_args->used) > 0 || self->is_init == false) { + // Maybe change PWM timer + if (args[ARG_freq].u_int > 0) { + self->freq = args[ARG_freq].u_int; + } + + // Set duty_u16 cycle? + uint32_t duty = args[ARG_duty_u16].u_int; + if (duty != 0) { + if (duty >= PWM_FULL_SCALE) { + mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE)); + } + self->duty_u16 = duty; + self->duty_ns = 0; + } + // Set duty_ns value? + duty = args[ARG_duty_ns].u_int; + if (duty != 0) { + self->duty_ns = duty; + self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns); + } + // Set center value? + int32_t center = args[ARG_center].u_int; + if (center >= 0) { + if (center >= PWM_FULL_SCALE) { + mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE)); + } + self->center = center; + } else { // Use alignment setting shortcut + if (args[ARG_align].u_int >= 0) { + uint8_t align = args[ARG_align].u_int & 3; // limit to 0..3 + if (align == PWM_BEGIN) { + self->center = self->duty_u16 / 2; + } else if (align == PWM_END) { + self->center = PWM_FULL_SCALE - self->duty_u16 / 2; + } else { + self->center = 32768; // Default value: mid. + } + } + } + + if (args[ARG_invert].u_int >= 0) { + self->invert = args[ARG_invert].u_int & (PWM_CHANNEL1 | PWM_CHANNEL2); + } + + if (args[ARG_sync].u_int >= 0) { + self->sync = args[ARG_sync].u_int != false && self->submodule != 0; + } + + if (args[ARG_xor].u_int >= 0) { + self->xor = args[ARG_xor].u_int & 0x03; + } + + if (args[ARG_deadtime].u_int >= 0) { + self->deadtime = args[ARG_deadtime].u_int; + } + configure_pwm(self); + self->is_init = true; + } else { + machine_pwm_start(self); + } + +} + +// PWM(pin | pin-tuple, freq, [args]) +STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // Check number of arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + mp_obj_t *pins; + const machine_pin_obj_t *pin1; + const machine_pin_obj_t *pin2; + + // Get referred Pin object(s) + if (mp_obj_is_type(args[0], &mp_type_tuple)) { + mp_obj_get_array_fixed_n(args[0], 2, &pins); + pin1 = pin_find(pins[0]); + pin2 = pin_find(pins[1]); + } else { + pin1 = pin_find(args[0]); + pin2 = NULL; + } + + // Check whether it supports PWM and decode submodule & channel + const machine_pin_af_obj_t *af_obj1 = NULL; + uint8_t submodule1; + uint8_t channel1; + const machine_pin_af_obj_t *af_obj2 = NULL; + uint8_t submodule2; + uint8_t channel2; + uint8_t module; + bool is_flexpwm = false; + + for (int i = 0; i < pin1->af_list_len; ++i) { + af_obj1 = af_name_decode_flexpwm(&(pin1->af_list[i]), &module, &submodule1, &channel1); + if (af_obj1 != NULL) { + break; + } + } + if (pin2 != NULL) { + for (int i = 0; i < pin1->af_list_len; ++i) { + af_obj2 = af_name_decode_flexpwm(&(pin2->af_list[i]), &module, &submodule2, &channel2); + if (af_obj2 != NULL) { + break; + } + } + } + if (af_obj1 == NULL) { + submodule1 = 0; + #ifdef FSL_FEATURE_SOC_TMR_COUNT + // Check for QTimer support + if (is_board_pin(pin1)) { + for (int i = 0; i < pin1->af_list_len; ++i) { + af_obj1 = af_name_decode_qtmr(&(pin1->af_list[i]), &module, &channel1); + if (af_obj1 != NULL) { + break; + } + } + } + #endif + if (af_obj1 == NULL) { + mp_raise_ValueError(MP_ERROR_TEXT("the requested Pin(s) does not support PWM")); + } + } else { + // is flexpwm, check for instance match + is_flexpwm = true; + if (pin2 != NULL && af_obj1->instance != af_obj2->instance && submodule1 != submodule2) { + mp_raise_ValueError(MP_ERROR_TEXT("the pins must be a A/B pair of a submodule")); + } + } + + // Create and populate the PWM object. + machine_pwm_obj_t *self = m_new_obj(machine_pwm_obj_t); + self->base.type = &machine_pwm_type; + self->is_flexpwm = is_flexpwm; + self->instance = af_obj1->instance; + self->module = module; + self->submodule = submodule1; + self->channel1 = channel1; + self->invert = 0; + self->freq = 1000; + self->prescale = -1; + self->duty_u16 = 32768; + self->duty_ns = 0; + self->center = 32768; + self->output_enable_1 = is_board_pin(pin1); + self->sync = false; + self->deadtime = 0; + self->xor = 0; + self->is_init = false; + + // Initialize the Pin(s). + CLOCK_EnableClock(kCLOCK_Iomuxc); // just in case it was not set yet + IOMUXC_SetPinMux(pin1->muxRegister, af_obj1->af_mode, af_obj1->input_register, af_obj1->input_daisy, + pin1->configRegister, 0U); + IOMUXC_SetPinConfig(pin1->muxRegister, af_obj1->af_mode, af_obj1->input_register, af_obj1->input_daisy, + pin1->configRegister, 0x10B0U); + + // Settings for the second pin, if given. + if (pin2 != NULL && pin2 != pin1) { + self->complementary = 1; + self->channel2 = channel2; + self->output_enable_2 = is_board_pin(pin2); + // Initialize the Pin(s) + IOMUXC_SetPinMux(pin2->muxRegister, af_obj2->af_mode, af_obj2->input_register, af_obj2->input_daisy, + pin2->configRegister, 0U); + IOMUXC_SetPinConfig(pin2->muxRegister, af_obj2->af_mode, af_obj2->input_register, af_obj2->input_daisy, + pin2->configRegister, 0x10B0U); + } else { + self->complementary = 0; + } + + // Process the remaining parameters. + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + mp_machine_pwm_init_helper(self, n_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +// Disable all PWM devices. Called on soft reset +void machine_pwm_deinit_all(void) { + static PWM_Type *const pwm_bases[] = PWM_BASE_PTRS; + + for (int i = 1; i < ARRAY_SIZE(pwm_bases); i++) { + PWM_StopTimer(pwm_bases[i], 0x0f); // Stop all submodules + pwm_bases[i]->OUTEN = 0; // Disable ouput on all submodules, all channels + } + + #ifdef FSL_FEATURE_SOC_TMR_COUNT + static TMR_Type *const tmr_bases[] = TMR_BASE_PTRS; + for (int i = 1; i < ARRAY_SIZE(tmr_bases); i++) { + for (int j = 0; j < 4; j++) { + QTMR_StopTimer(tmr_bases[i], j); // Stop all timers + } + } + #endif +} + +STATIC void machine_pwm_start(machine_pwm_obj_t *self) { + if (self->is_flexpwm) { + PWM_StartTimer(self->instance, 1 << self->submodule); + #ifdef FSL_FEATURE_SOC_TMR_COUNT + } else { + QTMR_StartTimer((TMR_Type *)self->instance, self->channel1, kQTMR_PriSrcRiseEdge); + #endif + } +} + +STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) { + if (self->is_flexpwm) { + PWM_StopTimer(self->instance, 1 << self->submodule); + #ifdef FSL_FEATURE_SOC_TMR_COUNT + } else { + QTMR_StopTimer((TMR_Type *)self->instance, self->channel1); + #endif + } +} + +mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(self->freq); +} + +void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) { + self->freq = freq; + configure_pwm(self); +} + +mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(self->duty_u16); +} + +void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty) { + if (duty >= 0) { + if (duty >= PWM_FULL_SCALE) { + mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE)); + } + self->duty_u16 = duty; + self->duty_ns = 0; + configure_pwm(self); + } +} + +mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(1000000000ULL / self->freq * self->duty_u16 / PWM_FULL_SCALE); +} + +void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty) { + if (duty >= 0) { + self->duty_ns = duty; + self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns); + configure_pwm(self); + } +} diff --git a/ports/mimxrt/machine_sdcard.c b/ports/mimxrt/machine_sdcard.c new file mode 100644 index 000000000..4a92aae00 --- /dev/null +++ b/ports/mimxrt/machine_sdcard.c @@ -0,0 +1,222 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#if MICROPY_PY_MACHINE_SDCARD + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" +#include "ticks.h" +#include "fsl_cache.h" + +#include "sdcard.h" + + +enum { SDCARD_INIT_ARG_ID }; + + +STATIC const mp_arg_t sdcard_init_allowed_args[] = { + [SDCARD_INIT_ARG_ID] = { MP_QSTR_id, MP_ARG_INT, {.u_int = 1} }, +}; + + +STATIC void machine_sdcard_init_helper(mimxrt_sdcard_obj_t *self) { + sdcard_init(self, 198000000UL); // Initialize SDCard Host with 198MHz base clock + sdcard_init_pins(self); + + ticks_delay_us64(2ULL * 1000ULL); // Wait 2ms to allow USDHC signals to settle/debounce +} + +STATIC mp_obj_t sdcard_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + + // Parse args + mp_arg_val_t args[MP_ARRAY_SIZE(sdcard_init_allowed_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(sdcard_init_allowed_args), sdcard_init_allowed_args, args); + + // Extract arguments + mp_int_t sdcard_id = args[SDCARD_INIT_ARG_ID].u_int; + + if (!(1 <= sdcard_id && sdcard_id <= MP_ARRAY_SIZE(mimxrt_sdcard_objs))) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "SDCard(%d) doesn't exist", sdcard_id)); + } + + mimxrt_sdcard_obj_t *self = &mimxrt_sdcard_objs[(sdcard_id - 1)]; + + // Initialize SDCard Host + if (!sdcard_state_initialized(self)) { + machine_sdcard_init_helper(self); + } + return MP_OBJ_FROM_PTR(self); +} + +// init() +STATIC mp_obj_t machine_sdcard_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + if (!sdcard_state_initialized(self)) { + machine_sdcard_init_helper(self); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_sdcard_init_obj, 1, machine_sdcard_init); + +// deinit() +STATIC mp_obj_t machine_sdcard_deinit(mp_obj_t self_in) { + mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + sdcard_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_sdcard_deinit_obj, machine_sdcard_deinit); + +// readblocks(block_num, buf) +STATIC mp_obj_t machine_sdcard_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + + if (sdcard_read(self, bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_DEFAULT_BLOCK_SIZE)) { + return MP_OBJ_NEW_SMALL_INT(0); + } else { + return MP_OBJ_NEW_SMALL_INT(-MP_EIO); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_readblocks_obj, machine_sdcard_readblocks); + +// present() +STATIC mp_obj_t machine_sdcard_present(mp_obj_t self_in) { + mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(sdcard_detect(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_sdcard_present_obj, machine_sdcard_present); + +STATIC mp_obj_t machine_sdcard_info(mp_obj_t self_in) { + mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (sdcard_detect(self) && sdcard_state_initialized(self)) { + uint32_t log_block_nbr = self->block_count; + uint32_t log_block_size = self->block_len; + + 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); + } else { + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_sdcard_info_obj, machine_sdcard_info); + +// writeblocks(block_num, buf) +STATIC mp_obj_t machine_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mimxrt_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + + if (sdcard_write(self, bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_DEFAULT_BLOCK_SIZE)) { + return MP_OBJ_NEW_SMALL_INT(0); + } else { + return MP_OBJ_NEW_SMALL_INT(-MP_EIO); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_writeblocks_obj, machine_sdcard_writeblocks); + +// ioctl(op, arg) +STATIC mp_obj_t machine_sdcard_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { + mimxrt_sdcard_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: { + if (sdcard_detect(self)) { + if (sdcard_power_on(self)) { + return MP_OBJ_NEW_SMALL_INT(0); + } else { + sdcard_power_off(self); + return MP_OBJ_NEW_SMALL_INT(-MP_EIO); // Initialization failed + } + } else { + return MP_OBJ_NEW_SMALL_INT(-MP_EIO); // Initialization failed + } + } + case MP_BLOCKDEV_IOCTL_DEINIT: { + if (sdcard_power_off(self)) { + return MP_OBJ_NEW_SMALL_INT(0); + } else { + return MP_OBJ_NEW_SMALL_INT(-MP_EIO); // Deinitialization failed + } + } + case MP_BLOCKDEV_IOCTL_SYNC: { + return MP_OBJ_NEW_SMALL_INT(0); + } + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: { + if (sdcard_state_initialized(self)) { + return MP_OBJ_NEW_SMALL_INT(self->block_count); + } else { + return MP_OBJ_NEW_SMALL_INT(-MP_EIO); // Card not initialized + } + } + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: { + if (sdcard_state_initialized(self)) { + return MP_OBJ_NEW_SMALL_INT(self->block_len); + } else { + return MP_OBJ_NEW_SMALL_INT(-MP_EIO); // Card not initialized + } + } + default: // unknown command + { + return mp_const_none; + } + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_ioctl_obj, machine_sdcard_ioctl); + +STATIC const mp_rom_map_elem_t sdcard_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_sdcard_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_sdcard_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_present), MP_ROM_PTR(&machine_sdcard_present_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_sdcard_info_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(sdcard_locals_dict, sdcard_locals_dict_table); + +const mp_obj_type_t machine_sdcard_type = { + { &mp_type_type }, + .name = MP_QSTR_SDCard, + .make_new = sdcard_obj_make_new, + .locals_dict = (mp_obj_dict_t *)&sdcard_locals_dict, +}; + +void machine_sdcard_init0(void) { + return; +} + +#endif // MICROPY_PY_MACHINE_SDCARD diff --git a/ports/mimxrt/machine_uart.c b/ports/mimxrt/machine_uart.c index abdb7ed97..9aa8a0c74 100644 --- a/ports/mimxrt/machine_uart.c +++ b/ports/mimxrt/machine_uart.c @@ -269,7 +269,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, // Get UART bus. int uart_id = mp_obj_get_int(args[0]); - if (uart_id < 1 || uart_id > MICROPY_HW_UART_NUM) { + if (uart_id < 0 || uart_id > MICROPY_HW_UART_NUM || uart_index_table[uart_id] == 0) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) doesn't exist"), uart_id); } @@ -286,11 +286,15 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, LPUART_GetDefaultConfig(&self->config); // Configure board-specific pin MUX based on the hardware device number. - lpuart_set_iomux(uart_hw_id); + bool uart_present = lpuart_set_iomux(uart_hw_id); - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - return machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args); + if (uart_present) { + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + return machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args); + } else { + return mp_const_none; + } } // uart.init(baud, [kwargs]) diff --git a/ports/mimxrt/machine_wdt.c b/ports/mimxrt/machine_wdt.c new file mode 100644 index 000000000..d09c464f6 --- /dev/null +++ b/ports/mimxrt/machine_wdt.c @@ -0,0 +1,107 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "modmachine.h" + +#include "fsl_wdog.h" + +#define MIN_TIMEOUT (500) +#define MAX_TIMEOUT (128000) + +typedef struct _machine_wdt_obj_t { + mp_obj_base_t base; +} machine_wdt_obj_t; + +STATIC const machine_wdt_obj_t machine_wdt = {{&machine_wdt_type}}; + +STATIC mp_obj_t machine_wdt_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_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} }, + }; + + // Parse the arguments. + 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); + + // Verify the WDT id. + mp_int_t id = args[ARG_id].u_int; + if (id != 0) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("WDT(%d) doesn't exist"), id); + } + + // Start the watchdog (timeout is in milliseconds). + wdog_config_t config; + WDOG_GetDefaultConfig(&config); + uint32_t timeout = args[ARG_timeout].u_int; + // confine to the valid range + if (timeout < MIN_TIMEOUT) { + timeout = MIN_TIMEOUT; + } else if (timeout > MAX_TIMEOUT) { + timeout = MAX_TIMEOUT; + } + config.timeoutValue = (timeout / 500) - 1; + WDOG_Init(WDOG1, &config); + + return MP_OBJ_FROM_PTR(&machine_wdt); +} + +STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { + (void)self_in; + WDOG_Refresh(WDOG1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); + +STATIC mp_obj_t machine_wdt_timeout_ms(mp_obj_t self_in, mp_obj_t timout_in) { + uint32_t timeout = mp_obj_get_int(timout_in); + // confine to the valid range + if (timeout < MIN_TIMEOUT) { + timeout = MIN_TIMEOUT; + } else if (timeout > MAX_TIMEOUT) { + timeout = MAX_TIMEOUT; + } + timeout = (timeout / 500) - 1; + WDOG_SetTimeoutValue(WDOG1, (uint16_t)timeout); + WDOG_Refresh(WDOG1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_wdt_timeout_ms_obj, machine_wdt_timeout_ms); + +STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) }, + { MP_ROM_QSTR(MP_QSTR_timeout_ms), MP_ROM_PTR(&machine_wdt_timeout_ms_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table); + +const mp_obj_type_t machine_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = machine_wdt_make_new, + .locals_dict = (mp_obj_dict_t *)&machine_wdt_locals_dict, +}; diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index e81974afa..a6a0d2e19 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -36,8 +36,16 @@ #include "ticks.h" #include "tusb.h" #include "led.h" +#include "pendsv.h" #include "modmachine.h" +#if MICROPY_PY_LWIP +#include "lwip/init.h" +#include "lwip/apps/mdns.h" +#endif +#include "systick.h" +#include "extmod/modnetwork.h" + extern uint8_t _sstack, _estack, _gc_heap_start, _gc_heap_end; void board_init(void); @@ -47,17 +55,29 @@ int main(void) { ticks_init(); tusb_init(); led_init(); + pendsv_init(); mp_stack_set_top(&_estack); mp_stack_set_limit(&_estack - &_sstack - 1024); + #if MICROPY_PY_LWIP + // lwIP doesn't allow to reinitialise itself by subsequent calls to this function + // because the system timeout list (next_timeout) is only ever reset by BSS clearing. + // So for now we only init the lwIP stack once on power-up. + lwip_init(); + #if LWIP_MDNS_RESPONDER + mdns_resp_init(); + #endif + systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); + #endif + for (;;) { gc_init(&_gc_heap_start, &_gc_heap_end); 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); + #if MICROPY_PY_NETWORK + mod_network_init(); + #endif // Initialise sub-systems. readline_init0(); @@ -93,6 +113,10 @@ int main(void) { soft_reset_exit: mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n"); machine_pin_irq_deinit(); + #if MICROPY_PY_NETWORK + mod_network_deinit(); + #endif + machine_pwm_deinit_all(); gc_sweep_all(); mp_deinit(); } @@ -137,17 +161,25 @@ const char mimxrt_help_text[] = " Pin pull modes are: Pin.PULL_UP, Pin.PULL_UP_47K, Pin.PULL_UP_22K, Pin.PULL_DOWN, Pin.PULL_HOLD\n" " machine.ADC(pin) -- make an analog object from a pin\n" " methods: read_u16()\n" - " machine.UART(id, baudrate=115200) -- create an UART object (id=1 - 8)\n" + " machine.UART(id, baudrate=115200) -- create an UART object (id=1 - 8, board-specific)\n" " methods: init(), write(buf), any()\n" " buf=read(n), readinto(buf), buf=readline()\n" " The RX and TX pins are fixed and board-specific.\n" - " machine.SoftI2C() -- create an Soft I2C object\n" + " machine.SoftI2C() -- create a Soft I2C object\n" + " machine.I2C(id) -- create a HW I2C object\n" " methods: readfrom(addr, buf, stop=True), writeto(addr, buf, stop=True)\n" " readfrom_mem(addr, memaddr, arg), writeto_mem(addr, memaddr, arg)\n" - " machine.SoftSPI(baudrate=1000000) -- create an SPI object ()\n" + " SoftI2C allows to use any pin for sda and scl, HW I2C id's and pins are fixed\n" + " machine.SoftSPI(baudrate=1000000) -- create a Soft SPI object\n" + " machine.SPI(id, baudrate=1000000) -- create a HW SPI object\n" " methods: read(nbytes, write=0x00), write(buf), write_readinto(wr_buf, rd_buf)\n" + " SoftSPI allows to use any pin for SPI, HW SPI id's and pins are fixed\n" " machine.Timer(id, freq, callback) -- create a hardware timer object (id=0,1,2)\n" " eg: machine.Timer(freq=1, callback=lambda t:print(t))\n" + " machine.RTC() -- create a Real Time Clock object\n" + " methods: init(), datetime([dateime_tuple]), now()\n" + " machine.PWM(pin, freq, duty_u16[, kw_opts]) -- create a PWM object\n" + " methods: init(), duty_u16([value]), duty_ns([value]), freq([value])\n" "\n" "Useful control commands:\n" " CTRL-C -- interrupt a running program\n" diff --git a/ports/mimxrt/mbedtls/mbedtls_config.h b/ports/mimxrt/mbedtls/mbedtls_config.h new file mode 100644 index 000000000..1ab748d8e --- /dev/null +++ b/ports/mimxrt/mbedtls/mbedtls_config.h @@ -0,0 +1,99 @@ +/* + * 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 + +// 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 +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +// #define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_ERROR_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/mimxrt/mbedtls/mbedtls_port.c b/ports/mimxrt/mbedtls/mbedtls_port.c new file mode 100644 index 000000000..eb11f5141 --- /dev/null +++ b/ports/mimxrt/mbedtls/mbedtls_port.c @@ -0,0 +1,93 @@ +/* + * 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. + */ + +#ifdef MICROPY_SSL_MBEDTLS + +#include "py/runtime.h" +#include "py/gc.h" +#include "fsl_trng.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) { + + // assumes that TRNG_Init was called during startup + *olen = len; + TRNG_GetRandomData(TRNG, output, len); + + return 0; +} + +#endif diff --git a/ports/mimxrt/mimxrt_flash.c b/ports/mimxrt/mimxrt_flash.c index 79c4e676d..27ab987ed 100644 --- a/ports/mimxrt/mimxrt_flash.c +++ b/ports/mimxrt/mimxrt_flash.c @@ -32,8 +32,6 @@ #include "modmimxrt.h" #include BOARD_FLASH_OPS_HEADER_H -// BOARD_FLASH_SIZE is defined in mpconfigport.h - #define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize) #define PAGE_SIZE_BYTES (qspiflash_config.pageSize) @@ -81,7 +79,7 @@ status_t flash_erase_block(uint32_t erase_addr) { // the vfs driver takes care for erasing the sector if required status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) __attribute__((section(".ram_functions"))); status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) { - status_t status; + status_t status = 0; uint32_t size; uint32_t next_addr; diff --git a/ports/mimxrt/mimxrt_sdram.c b/ports/mimxrt/mimxrt_sdram.c new file mode 100644 index 000000000..8c336bb60 --- /dev/null +++ b/ports/mimxrt/mimxrt_sdram.c @@ -0,0 +1,186 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#if MICROPY_HW_SDRAM_AVAIL + +#include "modmachine.h" +#include "fsl_semc.h" +#include "fsl_iomuxc.h" + +// Linker symbols +extern uint8_t __sdram_start; + + +void mimxrt_sdram_init(void) { + // Set Clocks + CLOCK_InitSysPfd(kCLOCK_Pfd2, 29); // '29' PLL2 PFD2 frequency = 528MHz * 18 / 29 = 327.72MHz (with 528MHz = PLL2 frequency) + CLOCK_SetMux(kCLOCK_SemcAltMux, 0); // '0' PLL2 PFD2 will be selected as alternative clock for SEMC root clock + CLOCK_SetMux(kCLOCK_SemcMux, 1); // '1' SEMC alternative clock will be used as SEMC clock root + CLOCK_SetDiv(kCLOCK_SemcDiv, 1); // '1' divide by 2 -> SEMC clock = 163.86 MHz + + // Set Pins + + // Data Pins + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA00, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA00, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA01, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA01, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA02, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA02, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA03, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA03, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA04, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA04, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA05, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA05, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA06, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA06, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA07, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA07, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA08, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA08, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA09, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA09, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA10, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA10, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA11, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA11, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA12, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA12, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA13, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA13, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA14, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA14, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA15, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA15, 0xE1UL); + + // Address Pins + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR00, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR00, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR01, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR01, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR02, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR02, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR03, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR03, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR04, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR04, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR05, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR05, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR06, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR06, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR07, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR07, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR08, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR08, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR09, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR09, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR10, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR10, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR11, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR11, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR12, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR12, 0xE1UL); + + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DM00, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM00, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_BA0, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_BA0, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_BA1, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_BA1, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CAS, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CAS, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_RAS, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_RAS, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CLK, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CLK, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CKE, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CKE, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_WE, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_WE, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DM01, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM01, 0xE1UL); + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DQS, 1UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DQS, 0xE1UL); + + // Chip Select Pins + #ifndef MIMXRT_IOMUXC_SEMC_CS0 + #error No SEMC CS0 defined! + #endif + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS0, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS0, 0xE1UL); + + #ifdef MIMXRT_IOMUXC_SEMC_CS1 + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS1, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS1, 0xE1UL); + #endif + + #ifdef MIMXRT_IOMUXC_SEMC_CS2 + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS2, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS2, 0xE1UL); + #endif + + #ifdef MIMXRT_IOMUXC_SEMC_CS3 + IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS3, 0UL); + IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS3, 0xE1UL); + #endif + + // Configure SEMC + semc_config_t semc_cfg; + SEMC_GetDefaultConfig(&semc_cfg); + + semc_cfg.dqsMode = kSEMC_Loopbackdqspad; // For more accurate timing. + SEMC_Init(SEMC, &semc_cfg); + + uint32_t clock_freq = CLOCK_GetFreq(kCLOCK_SemcClk); + semc_sdram_config_t sdram_cfg = { + .csxPinMux = kSEMC_MUXCSX0, + .address = ((uint32_t)&__sdram_start), + .memsize_kbytes = (MICROPY_HW_SDRAM_SIZE >> 10), // Right shift by 10 == division by 1024 + .portSize = kSEMC_PortSize16Bit, + .burstLen = kSEMC_Sdram_BurstLen1, + .columnAddrBitNum = kSEMC_SdramColunm_9bit, + .casLatency = kSEMC_LatencyThree, + .tPrecharge2Act_Ns = 18, // Trp 18ns + .tAct2ReadWrite_Ns = 18, // Trcd 18ns + .tRefreshRecovery_Ns = (60 + 67), + .tWriteRecovery_Ns = 12, // 12ns + .tCkeOff_Ns = 42, // The minimum cycle of SDRAM CLK off state. CKE is off in self refresh at a minimum period tRAS. + .tAct2Prechage_Ns = 42, // Tras 42ns + .tSelfRefRecovery_Ns = 67, + .tRefresh2Refresh_Ns = 60, + .tAct2Act_Ns = 60, + .tPrescalePeriod_Ns = 160 * (1000000000 / clock_freq), + .tIdleTimeout_Ns = 0UL, + .refreshPeriod_nsPerRow = 64 * 1000000 / 8192, // 64ms/8192 + .refreshUrgThreshold = 64 * 1000000 / 8192, // 64ms/8192 + .refreshBurstLen = 1 + }; + + (status_t)SEMC_ConfigureSDRAM(SEMC, kSEMC_SDRAM_CS0, &sdram_cfg, clock_freq); +} + +#endif diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c index 150615ca0..63cec0550 100644 --- a/ports/mimxrt/modmachine.c +++ b/ports/mimxrt/modmachine.c @@ -26,26 +26,64 @@ */ #include "py/runtime.h" +#include "extmod/machine_bitstream.h" #include "extmod/machine_mem.h" #include "extmod/machine_i2c.h" #include "extmod/machine_pulse.h" #include "extmod/machine_signal.h" #include "extmod/machine_spi.h" +#include "shared/runtime/pyexec.h" #include "led.h" #include "pin.h" #include "modmachine.h" #include "fsl_clock.h" +#include "fsl_wdog.h" #include CPU_HEADER_H +typedef enum { + MP_PWRON_RESET = 1, + MP_HARD_RESET, + MP_WDT_RESET, + MP_DEEPSLEEP_RESET, + MP_SOFT_RESET +} reset_reason_t; + +STATIC mp_obj_t machine_unique_id(void) { + unsigned char id[8]; + mp_hal_get_unique_id(id); + return mp_obj_new_bytes(id, sizeof(id)); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); + +STATIC mp_obj_t machine_soft_reset(void) { + pyexec_system_exit = PYEXEC_FORCED_EXIT; + mp_raise_type(&mp_type_SystemExit); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); + STATIC mp_obj_t machine_reset(void) { - NVIC_SystemReset(); + WDOG_TriggerSystemSoftwareReset(WDOG1); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); +STATIC mp_obj_t machine_reset_cause(void) { + uint16_t reset_cause = + WDOG_GetStatusFlags(WDOG1) & (kWDOG_PowerOnResetFlag | kWDOG_TimeoutResetFlag | kWDOG_SoftwareResetFlag); + if (reset_cause == kWDOG_PowerOnResetFlag) { + reset_cause = MP_PWRON_RESET; + } else if (reset_cause == kWDOG_TimeoutResetFlag) { + reset_cause = MP_WDT_RESET; + } else { + reset_cause = MP_SOFT_RESET; + } + return MP_OBJ_NEW_SMALL_INT(reset_cause); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); + STATIC mp_obj_t machine_freq(void) { - return MP_OBJ_NEW_SMALL_INT(CLOCK_GetFreq(kCLOCK_CpuClk)); + return MP_OBJ_NEW_SMALL_INT(mp_hal_get_cpu_freq()); } MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq); @@ -70,7 +108,10 @@ MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq); STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_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) }, @@ -82,19 +123,32 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, + #if MICROPY_PY_MACHINE_SDCARD + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&machine_sdcard_type) }, + #endif + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, { MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, + { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) }, { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + #if MICROPY_PY_MACHINE_BITSTREAM + { MP_ROM_QSTR(MP_QSTR_bitstream), MP_ROM_PTR(&machine_bitstream_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + + // Reset reasons + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(MP_WDT_RESET) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(MP_SOFT_RESET) }, }; STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h index 9732093bd..d18a22762 100644 --- a/ports/mimxrt/modmachine.h +++ b/ports/mimxrt/modmachine.h @@ -30,14 +30,20 @@ #include "py/obj.h" extern const mp_obj_type_t machine_adc_type; -extern const mp_obj_type_t machine_timer_type; -extern const mp_obj_type_t machine_rtc_type; extern const mp_obj_type_t machine_i2c_type; +extern const mp_obj_type_t machine_pwm_type; +extern const mp_obj_type_t machine_rtc_type; +extern const mp_obj_type_t machine_sdcard_type; extern const mp_obj_type_t machine_spi_type; +extern const mp_obj_type_t machine_timer_type; extern const mp_obj_type_t machine_uart_type; +extern const mp_obj_type_t machine_wdt_type; void machine_adc_init(void); void machine_pin_irq_deinit(void); +void machine_pwm_deinit_all(void); void machine_timer_init_PIT(void); +void machine_sdcard_init0(void); +void mimxrt_sdram_init(void); #endif // MICROPY_INCLUDED_MIMXRT_MODMACHINE_H diff --git a/ports/mimxrt/modmimxrt.c b/ports/mimxrt/modmimxrt.c index addd4ba4d..041a72f7f 100644 --- a/ports/mimxrt/modmimxrt.c +++ b/ports/mimxrt/modmimxrt.c @@ -24,12 +24,16 @@ * THE SOFTWARE. */ +#include "py/mperrno.h" #include "py/runtime.h" +#include "drivers/dht/dht.h" #include "modmimxrt.h" STATIC const mp_rom_map_elem_t mimxrt_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mimxrt) }, { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&mimxrt_flash_type) }, + + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mimxrt_module_globals, mimxrt_module_globals_table); diff --git a/ports/mimxrt/modules/_boot.py b/ports/mimxrt/modules/_boot.py index 892d00473..bc8d72224 100644 --- a/ports/mimxrt/modules/_boot.py +++ b/ports/mimxrt/modules/_boot.py @@ -3,13 +3,32 @@ # Note: the flash requires the programming size to be aligned to 256 bytes. import os +import sys import mimxrt +from machine import Pin bdev = mimxrt.Flash() - try: vfs = os.VfsLfs2(bdev, progsize=256) except: os.VfsLfs2.mkfs(bdev, progsize=256) vfs = os.VfsLfs2(bdev, progsize=256) -os.mount(vfs, "/") +os.mount(vfs, "/flash") +os.chdir("/flash") +sys.path.append("/flash") + +# do not mount the SD card if SKIPSD exists. +try: + os.stat("SKIPSD") +except: + try: + from machine import SDCard + + sdcard = SDCard(1) + + fat = os.VfsFat(sdcard) + os.mount(fat, "/sdcard") + os.chdir("/sdcard") + sys.path.append("/sdcard") + except: + pass # Fail silently diff --git a/ports/mimxrt/moduos.c b/ports/mimxrt/moduos.c index 225cd4ddd..b59a5f448 100644 --- a/ports/mimxrt/moduos.c +++ b/ports/mimxrt/moduos.c @@ -30,7 +30,10 @@ #include "py/objstr.h" #include "py/runtime.h" +#include "py/mphal.h" +#include "extmod/misc.h" #include "extmod/vfs.h" +#include "extmod/vfs_fat.h" #include "extmod/vfs_lfs.h" #include "genhdr/mpversion.h" #include "fsl_trng.h" @@ -95,6 +98,21 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); +#if MICROPY_PY_OS_DUPTERM +STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { + (void)obj_in; + for (;;) { + int c = mp_uos_dupterm_rx_chr(); + if (c < 0) { + break; + } + ringbuf_put(&stdin_ringbuf, c); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify); +#endif + STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, @@ -117,6 +135,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { #if MICROPY_PY_OS_DUPTERM { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) }, #endif #if MICROPY_VFS diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 1066b93e1..e650579e6 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -43,8 +43,9 @@ uint32_t trng_random_u32(void); #define MICROPY_EMIT_THUMB (1) #define MICROPY_EMIT_INLINE_THUMB (1) -// Compiler configuration -#define MICROPY_COMP_CONST (0) +// Optimisations +#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1) +#define MICROPY_OPT_MAP_LOOKUP_CACHE (1) // Python internal features #define MICROPY_READER_VFS (1) @@ -71,6 +72,7 @@ uint32_t trng_random_u32(void); #define MICROPY_PY_FUNCTION_ATTRS (1) #define MICROPY_PY_DESCRIPTORS (1) #define MICROPY_PY_DELATTR_SETATTR (1) +#define MICROPY_PY_FSTRINGS (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_STR_CENTER (1) #define MICROPY_PY_BUILTINS_STR_PARTITION (1) @@ -114,20 +116,62 @@ uint32_t trng_random_u32(void); #define MICROPY_PY_URE_MATCH_GROUPS (1) #define MICROPY_PY_URE_MATCH_SPAN_START_END (1) #define MICROPY_PY_URE_SUB (1) +#define MICROPY_PY_USSL_FINALISER (MICROPY_PY_USSL) #define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_UBINASCII (1) #define MICROPY_PY_UBINASCII_CRC32 (1) #define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_OS_DUPTERM (3) #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) #define MICROPY_PY_URANDOM_SEED_INIT_FUNC (trng_random_u32()) #define MICROPY_PY_USELECT (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_PY_MACHINE_BITSTREAM (1) #define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_PWM (1) +#define MICROPY_PY_MACHINE_PWM_INIT (1) +#define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS (1) +#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/mimxrt/machine_pwm.c" #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SOFTI2C (1) #define MICROPY_PY_MACHINE_SPI (1) +#define MICROPY_PY_MACHINE_SOFTSPI (1) #define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_ONEWIRE (1) +#define MICROPY_PY_UPLATFORM (1) + +// fatfs configuration used in ffconf.h +#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) */ + +// If MICROPY_PY_LWIP is defined, add network support +#if MICROPY_PY_LWIP + +#define MICROPY_PY_NETWORK (1) +#define MICROPY_PY_USOCKET (1) +#define MICROPY_PY_UWEBSOCKET (1) +#define MICROPY_PY_WEBREPL (1) +#define MICROPY_PY_UHASHLIB_SHA1 (1) +#define MICROPY_PY_LWIP_SOCK_RAW (1) +#define MICROPY_HW_ETH_MDC (1) + +// Prevent the "LWIP task" from running. +#define MICROPY_PY_LWIP_ENTER MICROPY_PY_PENDSV_ENTER +#define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER +#define MICROPY_PY_LWIP_EXIT MICROPY_PY_PENDSV_EXIT + +#endif + +// For regular code that wants to prevent "background tasks" from running. +// These background tasks (LWIP, Bluetooth) run in PENDSV context. +// TODO: Check for the settings of the STM32 port in irq.h +#define MICROPY_PY_PENDSV_ENTER uint32_t atomic_state = disable_irq(); +#define MICROPY_PY_PENDSV_REENTER atomic_state = disable_irq(); +#define MICROPY_PY_PENDSV_EXIT enable_irq(atomic_state); // Use VfsLfs2's types for fileio/textio #define mp_type_fileio mp_type_vfs_lfs2_fileio @@ -135,6 +179,7 @@ uint32_t trng_random_u32(void); // Use VFS's functions for import stat and builtin open #define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open #define mp_builtin_open_obj mp_vfs_open_obj // Hooks to add builtins @@ -149,6 +194,23 @@ __attribute__((always_inline)) static inline uint32_t disable_irq(void) { return state; } +static inline uint32_t raise_irq_pri(uint32_t pri) { + uint32_t basepri = __get_BASEPRI(); + // If non-zero, the processor does not process any exception with a + // priority value greater than or equal to BASEPRI. + // When writing to BASEPRI_MAX the write goes to BASEPRI only if either: + // - Rn is non-zero and the current BASEPRI value is 0 + // - Rn is non-zero and less than the current BASEPRI value + pri <<= (8 - __NVIC_PRIO_BITS); + __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); + return basepri; +} + +// "basepri" should be the value returned from raise_irq_pri +static inline void restore_irq_pri(uint32_t basepri) { + __set_BASEPRI(basepri); +} + #define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq() #define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state) @@ -160,6 +222,38 @@ extern const struct _mp_obj_module_t mp_module_mimxrt; extern const struct _mp_obj_module_t mp_module_onewire; 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; + +#if MICROPY_PY_NETWORK +#define NETWORK_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) }, +#else +#define NETWORK_BUILTIN_MODULE +#endif + +#if MICROPY_PY_USOCKET && MICROPY_PY_LWIP +// usocket implementation provided by lwIP +#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) }, +#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) }, +#else +// no usocket module +#define SOCKET_BUILTIN_MODULE +#endif + +#if MICROPY_SSL_MBEDTLS +#define MICROPY_PORT_ROOT_POINTER_MBEDTLS void **mbedtls_memory; +#else +#define MICROPY_PORT_ROOT_POINTER_MBEDTLS +#endif + +#if defined(MICROPY_HW_ETH_MDC) +extern const struct _mp_obj_type_t network_lan_type; +#define MICROPY_HW_NIC_ETH { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) }, +#else +#define MICROPY_HW_NIC_ETH +#endif #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ @@ -167,6 +261,11 @@ extern const struct _mp_obj_module_t mp_module_utime; { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \ + SOCKET_BUILTIN_MODULE \ + NETWORK_BUILTIN_MODULE \ + +#define MICROPY_PORT_NETWORK_INTERFACES \ + MICROPY_HW_NIC_ETH \ #define MICROPY_HW_PIT_NUM_CHANNELS 3 @@ -174,6 +273,10 @@ extern const struct _mp_obj_module_t mp_module_utime; const char *readline_hist[8]; \ struct _machine_timer_obj_t *timer_table[MICROPY_HW_PIT_NUM_CHANNELS]; \ void *machine_pin_irq_objects[MICROPY_HW_NUM_PIN_IRQS]; \ + /* list of registered NICs */ \ + mp_obj_list_t mod_network_nic_list; \ + /* root pointers for sub-systems */ \ + MICROPY_PORT_ROOT_POINTER_MBEDTLS \ #define MP_STATE_PORT MP_STATE_VM diff --git a/ports/mimxrt/mphalport.c b/ports/mimxrt/mphalport.c index ff7e988df..17a6898c4 100644 --- a/ports/mimxrt/mphalport.c +++ b/ports/mimxrt/mphalport.c @@ -29,14 +29,21 @@ #include "py/stream.h" #include "py/mphal.h" #include "shared/timeutils/timeutils.h" +#include "extmod/misc.h" #include "ticks.h" #include "tusb.h" #include "fsl_snvs_lp.h" +#include "fsl_ocotp.h" #include CPU_HEADER_H +STATIC uint8_t stdin_ringbuf_array[260]; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; + #if MICROPY_KBD_EXCEPTION +int mp_interrupt_char = -1; + void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { (void)itf; (void)wanted_char; @@ -45,6 +52,7 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { } void mp_hal_set_interrupt_char(int c) { + mp_interrupt_char = c; tud_cdc_set_wanted_char(c); } @@ -52,6 +60,9 @@ void mp_hal_set_interrupt_char(int c) { uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { uintptr_t ret = 0; + if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) { + ret |= MP_STREAM_POLL_RD; + } if (tud_cdc_connected() && tud_cdc_available()) { ret |= MP_STREAM_POLL_RD; } @@ -64,6 +75,10 @@ int mp_hal_stdin_rx_chr(void) { // if (USARTx->USART.INTFLAG.bit.RXC) { // return USARTx->USART.DATA.bit.DATA; // } + int c = ringbuf_get(&stdin_ringbuf); + if (c != -1) { + return c; + } if (tud_cdc_connected() && tud_cdc_available()) { uint8_t buf[1]; uint32_t count = tud_cdc_read(buf, sizeof(buf)); @@ -90,6 +105,7 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { i += n2; } } + mp_uos_dupterm_tx_strn(str, len); // TODO // while (len--) { // while (!(USARTx->USART.INTFLAG.bit.DRE)) { } @@ -103,3 +119,41 @@ uint64_t mp_hal_time_ns(void) { uint64_t s = timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.minute, t.second); return s * 1000000000ULL; } + +/*******************************************************************************/ +// MAC address + +void mp_hal_get_unique_id(uint8_t id[]) { + OCOTP_Init(OCOTP, CLOCK_GetFreq(kCLOCK_IpgClk)); + *(uint32_t *)&id[0] = OCOTP->CFG0; + *(uint32_t *)&id[4] = OCOTP->CFG1; +} + +// Generate a random locally administered MAC address (LAA) +void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]) { + // Take the MAC addr from the OTP's Configuration and Manufacturing Info + unsigned char id[8]; + mp_hal_get_unique_id(id); + + uint32_t pt1 = *(uint32_t *)&id[0]; + uint32_t pt2 = *(uint32_t *)&id[4]; + + buf[0] = 0x02; // Locally Administered MAC + *(uint32_t *)&buf[1] = pt1 ^ (pt1 >> 8); + *(uint16_t *)&buf[4] = (uint16_t)(pt2 ^ pt2 >> 16); + buf[5] ^= (uint8_t)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]; + 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/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h index 94f43001d..124b90560 100644 --- a/ports/mimxrt/mphalport.h +++ b/ports/mimxrt/mphalport.h @@ -29,9 +29,14 @@ #include #include "ticks.h" +#include "py/ringbuf.h" #include "pin.h" +#include "fsl_clock.h" + +#define MICROPY_HAL_VERSION "2.8.0" #define MP_HAL_PIN_FMT "%q" +extern ringbuf_t stdin_ringbuf; #define mp_hal_pin_obj_t const machine_pin_obj_t * #define mp_hal_get_pin_obj(o) pin_find(o) @@ -39,8 +44,8 @@ #define mp_hal_pin_input(p) machine_pin_set_mode(p, PIN_MODE_IN); #define mp_hal_pin_output(p) machine_pin_set_mode(p, PIN_MODE_OUT); #define mp_hal_pin_open_drain(p) machine_pin_set_mode(p, PIN_MODE_OPEN_DRAIN); -#define mp_hal_pin_high(p) (GPIO_PinWrite(p->gpio, p->pin, 1U)) -#define mp_hal_pin_low(p) (GPIO_PinWrite(p->gpio, p->pin, 0U)) +#define mp_hal_pin_high(p) (p->gpio->DR_SET = 1 << p->pin) +#define mp_hal_pin_low(p) (p->gpio->DR_CLEAR = 1 << p->pin) #define mp_hal_pin_write(p, value) (GPIO_PinWrite(p->gpio, p->pin, value)) #define mp_hal_pin_toggle(p) (GPIO_PortToggle(p->gpio, (1 << p->pin))) #define mp_hal_pin_read(p) (GPIO_PinReadPadStatus(p->gpio, p->pin)) @@ -48,8 +53,8 @@ #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_quiet_timing_enter() MICROPY_BEGIN_ATOMIC_SECTION() -#define mp_hal_quiet_timing_exit(irq_state) MICROPY_END_ATOMIC_SECTION(irq_state) +#define mp_hal_quiet_timing_enter() raise_irq_pri(1) +#define mp_hal_quiet_timing_exit(irq_state) restore_irq_pri(irq_state) void mp_hal_set_interrupt_char(int c); @@ -72,9 +77,32 @@ static inline void mp_hal_delay_us(mp_uint_t us) { #define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) -static inline mp_uint_t mp_hal_ticks_cpu(void) { - return 0; +static inline void mp_hal_ticks_cpu_enable(void) { + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->LAR = 0xc5acce55; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } +static inline mp_uint_t mp_hal_ticks_cpu(void) { + return DWT->CYCCNT; +} + +static inline mp_uint_t mp_hal_get_cpu_freq(void) { + return CLOCK_GetCpuClkFreq(); +} + +enum { + MP_HAL_MAC_WLAN0 = 0, + MP_HAL_MAC_WLAN1, + MP_HAL_MAC_BDADDR, + MP_HAL_MAC_ETH0, + MP_HAL_MAC_ETH1, +}; + +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); +void mp_hal_get_unique_id(uint8_t id[]); #endif // MICROPY_INCLUDED_MIMXRT_MPHALPORT_H diff --git a/ports/mimxrt/mpnetworkport.c b/ports/mimxrt/mpnetworkport.c new file mode 100644 index 000000000..2e6a49b90 --- /dev/null +++ b/ports/mimxrt/mpnetworkport.c @@ -0,0 +1,64 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "shared/netutils/netutils.h" +#include "systick.h" +#include "pendsv.h" +#include "extmod/modnetwork.h" + +#if MICROPY_PY_LWIP +#include "lwip/netif.h" +#include "lwip/timeouts.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" +#include "lwip/apps/mdns.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(); +} + +STATIC void pyb_lwip_poll(void) { + // Run the lwIP internal updates + 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 // MICROPY_PY_LWIP diff --git a/ports/mimxrt/network_lan.c b/ports/mimxrt/network_lan.c new file mode 100644 index 000000000..5517b54bd --- /dev/null +++ b/ports/mimxrt/network_lan.c @@ -0,0 +1,231 @@ +/* + * 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 "extmod/modnetwork.h" + +#if defined(MICROPY_HW_ETH_MDC) + +#include "fsl_phy.h" +#include "eth.h" +#include "hal/phy/device/phyksz8081/fsl_phyksz8081.h" +#include "hal/phy/device/phydp83825/fsl_phydp83825.h" +#include "hal/phy/device/phydp83848/fsl_phydp83848.h" +#include "hal/phy/device/phylan8720/fsl_phylan8720.h" + +#include "lwip/netif.h" + +#ifndef ENET_TX_CLK_OUTPUT +#define ENET_TX_CLK_OUTPUT true +#endif + +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 *all_args) { + enum { ARG_id, ARG_phy_type, ARG_phy_addr, ARG_phy_clock}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ENET_PHY_ADDRESS} }, + { MP_QSTR_phy_clock, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ENET_TX_CLK_OUTPUT} }, + }; + // 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); + + const phy_operations_t *phy_ops = &ENET_PHY_OPS; + + // Select PHY driver + int phy_type = args[ARG_phy_type].u_int; + if (phy_type != -1) { + if (phy_type == PHY_KSZ8081) { + phy_ops = &phyksz8081_ops; + } else if (phy_type == PHY_DP83825) { + phy_ops = &phydp83825_ops; + } else if (phy_type == PHY_DP83848) { + phy_ops = &phydp83848_ops; + } else if (phy_type == PHY_LAN8720) { + phy_ops = &phylan8720_ops; + } else { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid value %d for phy"), phy_type); + } + } + int phy_addr = args[ARG_phy_addr].u_int; + + bool phy_clock = args[ARG_phy_clock].u_int; + + // Prepare for two ETH interfaces. + const network_lan_obj_t *self; + int mac_id = args[ARG_id].u_int; + if (mac_id == 0) { + self = &network_lan_eth0; + mac_id = MP_HAL_MAC_ETH0; + } else if (mac_id == 1) { + self = &network_lan_eth0; + mac_id = MP_HAL_MAC_ETH1; + } else { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid LAN interface %d"), mac_id); + } + + eth_init(self->eth, mac_id, phy_ops, phy_addr, phy_clock); + // register with network module + mod_network_register_nic((mp_obj_t *)self); + 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(MP_ERROR_TEXT("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(MP_ERROR_TEXT("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(MP_ERROR_TEXT("unknown config param")); + } + } else { + // Set config value(s) + if (n_args != 1) { + mp_raise_TypeError(MP_ERROR_TEXT("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; + } + case MP_QSTR_low_power: { + eth_low_power_mode(self->eth, mp_obj_get_int(e->value)); + break; + } + default: + mp_raise_ValueError(MP_ERROR_TEXT("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) }, + + { MP_ROM_QSTR(MP_QSTR_PHY_KSZ8081), MP_ROM_INT(PHY_KSZ8081) }, + { MP_ROM_QSTR(MP_QSTR_PHY_DP83825), MP_ROM_INT(PHY_DP83825) }, + { MP_ROM_QSTR(MP_QSTR_PHY_DP83848), MP_ROM_INT(PHY_DP83848) }, + { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) }, + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(PHY_TX_CLK_IN) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(PHY_TX_CLK_OUT) }, +}; +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) diff --git a/ports/mimxrt/pendsv.c b/ports/mimxrt/pendsv.c new file mode 100644 index 000000000..7638b160d --- /dev/null +++ b/ports/mimxrt/pendsv.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "shared/runtime/interrupt_char.h" +#include "pendsv.h" +#include "lib/nxp_driver/sdk/CMSIS/Include/core_cm7.h" + +#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003) +#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 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 defined(PENDSV_DISPATCH_NUM_SLOTS) + pendsv_dispatch_active = false; + #endif + + // set PendSV interrupt at lowest priority + NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV); +} + +#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; + 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_t f = pendsv_dispatch_table[i]; + pendsv_dispatch_table[i] = NULL; + f(); + } + } +} + +void PendSV_Handler(void) { + if (pendsv_dispatch_active) { + pendsv_dispatch_handler(); + } +} +#endif diff --git a/ports/mimxrt/pendsv.h b/ports/mimxrt/pendsv.h new file mode 100644 index 000000000..64883c903 --- /dev/null +++ b/ports/mimxrt/pendsv.h @@ -0,0 +1,44 @@ +/* + * 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. + */ +#ifndef MICROPY_INCLUDED_STM32_PENDSV_H +#define MICROPY_INCLUDED_STM32_PENDSV_H + +enum { + PENDSV_DISPATCH_SOFT_TIMER, // For later & for having at least one entry + #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP + PENDSV_DISPATCH_LWIP, + #endif + PENDSV_DISPATCH_MAX +}; + +#define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX + +typedef void (*pendsv_dispatch_t)(void); + +void pendsv_init(void); +void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f); + +#endif // MICROPY_INCLUDED_STM32_PENDSV_H diff --git a/ports/mimxrt/pin.c b/ports/mimxrt/pin.c index 7a437661e..964fb537b 100644 --- a/ports/mimxrt/pin.c +++ b/ports/mimxrt/pin.c @@ -116,6 +116,21 @@ const machine_pin_af_obj_t *pin_find_af(const machine_pin_obj_t *pin, uint8_t fn return NULL; } +const machine_pin_af_obj_t *pin_find_af_by_base(const machine_pin_obj_t *pin, void *base_ptr[], size_t base_size) { + const machine_pin_af_obj_t *af_obj = NULL; + + for (int i = 0; i < pin->af_list_len; ++i) { + af_obj = &pin->af_list[i]; + for (int j = 0; j < base_size; ++j) { + if (af_obj->instance == base_ptr[j]) { + return af_obj; + } + } + } + + return NULL; +} + const machine_pin_af_obj_t *pin_find_af_by_index(const machine_pin_obj_t *pin, mp_uint_t af_idx) { // TODO: Implement pin_find_af_by_index function return NULL; diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h index 8d80490d1..22e7a7e0f 100644 --- a/ports/mimxrt/pin.h +++ b/ports/mimxrt/pin.h @@ -58,7 +58,8 @@ enum { }; enum { - PIN_AF_MODE_ALT1 = 1, + PIN_AF_MODE_ALT0 = 0, + PIN_AF_MODE_ALT1, PIN_AF_MODE_ALT2, PIN_AF_MODE_ALT3, PIN_AF_MODE_ALT4, @@ -66,6 +67,7 @@ enum { PIN_AF_MODE_ALT6, PIN_AF_MODE_ALT7, PIN_AF_MODE_ALT8, + PIN_AF_MODE_ALT9, }; enum { @@ -97,7 +99,9 @@ typedef struct { mp_obj_base_t base; qstr name; // port name uint8_t af_mode; // alternate function + uint8_t input_daisy; void *instance; // pointer to peripheral instance for alternate function + uint32_t input_register; uint32_t pad_config; // pad configuration for alternate function } machine_pin_af_obj_t; diff --git a/ports/mimxrt/sdcard.c b/ports/mimxrt/sdcard.c new file mode 100644 index 000000000..fd3c91083 --- /dev/null +++ b/ports/mimxrt/sdcard.c @@ -0,0 +1,1023 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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. + */ + +#if MICROPY_PY_MACHINE_SDCARD + +#include "sdcard.h" +#include "ticks.h" +#include "fsl_iomuxc.h" + +#define SDCARD_VOLTAGE_WINDOW_SD (0x80100000U) +#define SDCARD_HIGH_CAPACITY (0x40000000U) +#define SDCARD_SWITCH_1_8V_CAPACITY ((uint32_t)0x01000000U) +#define SDCARD_MAX_VOLT_TRIAL ((uint32_t)0x000000FFU) + +// Error +#define SDCARD_STATUS_OUT_OF_RANGE_SHIFT (31U) +#define SDCARD_STATUS_ADDRESS_ERROR_SHIFT (30U) +#define SDCARD_STATUS_BLOCK_LEN_ERROR_SHIFT (29U) +#define SDCARD_STATUS_ERASE_SEQ_ERROR_SHIFT (28U) +#define SDCARD_STATUS_ERASE_PARAM_SHIFT (27U) +#define SDCARD_STATUS_WP_VIOLATION_SHIFT (26U) +#define SDCARD_STATUS_LOCK_UNLOCK_FAILED_SHIFT (24U) +#define SDCARD_STATUS_COM_CRC_ERROR_SHIFT (23U) +#define SDCARD_STATUS_ILLEGAL_COMMAND_SHIFT (22U) +#define SDCARD_STATUS_CARD_ECC_FAILED_SHIFT (21U) +#define SDCARD_STATUS_CC_ERROR_SHIFT (20U) +#define SDCARD_STATUS_ERROR_SHIFT (19U) +#define SDCARD_STATUS_CSD_OVERWRITE_SHIFT (16U) +#define SDCARD_STATUS_WP_ERASE_SKIP_SHIFT (15U) +#define SDCARD_STATUS_AUTH_SEQ_ERR_SHIFT (3U) + +// Status Flags +#define SDCARD_STATUS_CARD_IS_LOCKED_SHIFT (25U) +#define SDCARD_STATUS_CARD_ECC_DISABLED_SHIFT (14U) +#define SDCARD_STATUS_ERASE_RESET_SHIFT (13U) +#define SDCARD_STATUS_READY_FOR_DATA_SHIFT (8U) +#define SDCARD_STATUS_FX_EVENT_SHIFT (6U) +#define SDCARD_STATUS_APP_CMD_SHIFT (5U) + +#define SDMMC_MASK(bit) (1U << (bit)) +#define SDMMC_R1_ALL_ERROR_FLAG \ + (SDMMC_MASK(SDCARD_STATUS_OUT_OF_RANGE_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_ADDRESS_ERROR_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_BLOCK_LEN_ERROR_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_ERASE_SEQ_ERROR_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_ERASE_PARAM_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_WP_VIOLATION_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_LOCK_UNLOCK_FAILED_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_COM_CRC_ERROR_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_ILLEGAL_COMMAND_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_CARD_ECC_FAILED_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_CC_ERROR_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_ERROR_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_CSD_OVERWRITE_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_WP_ERASE_SKIP_SHIFT)) | \ + (SDMMC_MASK(SDCARD_STATUS_AUTH_SEQ_ERR_SHIFT)) + +#define SDMMC_R1_CURRENT_STATE(x) (((x) & 0x00001E00U) >> 9U) + +// --- +// SD Card command identifiers +// --- +enum +{ + SDCARD_CMD_GO_IDLE_STATE = 0U, + SDCARD_CMD_ALL_SEND_CID = 2U, + SDCARD_CMD_SEND_REL_ADDR = 3U, + SDCARD_CMD_SET_DSR = 4U, + SDCARD_CMD_SELECT_CARD = 7U, + SDCARD_CMD_SEND_IF_COND = 8U, + SDCARD_CMD_SEND_CSD = 9U, + SDCARD_CMD_SEND_CID = 10U, + SDCARD_CMD_STOP_TRANSMISSION = 12U, + SDCARD_CMD_SEND_STATUS = 13U, + SDCARD_CMD_GO_INACTIVE_STATE = 15U, + SDCARD_CMD_SET_BLOCKLENGTH = 16U, + SDCARD_CMD_READ_SINGLE_BLOCK = 17U, + SDCARD_CMD_READ_MULTIPLE_BLOCK = 18U, + SDCARD_CMD_SET_BLOCK_COUNT = 23U, + SDCARD_CMD_WRITE_SINGLE_BLOCK = 24U, + SDCARD_CMD_WRITE_MULTIPLE_BLOCK = 25U, + SDCARD_CMD_PROGRAM_CSD = 27U, + SDCARD_CMD_SET_WRITE_PROTECT = 28U, + SDCARD_CMD_CLEAR_WRITE_PROTECT = 29U, + SDCARD_CMD_SEND_WRITE_PROTECT = 30U, + SDCARD_CMD_ERASE = 38U, + SDCARD_CMD_LOCK_UNLOCK = 42U, + SDCARD_CMD_APP_CMD = 55U, + SDCARD_CMD_GEN_CMD = 56U, + SDCARD_CMD_READ_OCR = 58U, +}; + +// --- +// SD Card application command identifiers +// --- +enum +{ + SDCARD_ACMD_SET_BUS_WIDTH = 6U, + SDCARD_ACMD_SD_SEND_OP_COND = 41U, +}; + +// --- +// SD Card state identifiers +// --- +enum +{ + SDCARD_STATE_IDLE = 0U, + SDCARD_STATE_READY = 1U, + SDCARD_STATE_IDENTIFY = 2U, + SDCARD_STATE_STANDBY = 3U, + SDCARD_STATE_TRANSFER = 4U, + SDCARD_STATE_SENDDATA = 5U, + SDCARD_STATE_RECEIVEDATA = 6U, + SDCARD_STATE_PROGRAM = 7U, + SDCARD_STATE_DISCONNECT = 8U, +}; + +// --- +// SD Card transfer status +// --- +typedef enum +{ + SDCARD_TRANSFER_SUCCESS = 0, + SDCARD_TRANSFER_ERROR, + SDCARD_TRANSFER_PENDING +} sdcard_transfer_status_t; + +// --- +// SD Card type definitions +// --- +typedef struct _cid_t { + uint8_t reserved_0; + uint16_t mdt : 12; + uint16_t reserved_1 : 4; + uint32_t psn; + uint8_t prv; + char pnm[6]; + uint16_t oid; + uint8_t mid; +} __attribute__((packed)) cid_t; + +typedef struct _csd_t { + uint32_t data[4]; +} __attribute__((packed)) csd_t; + +typedef struct _csr_t { + uint32_t data[2]; +} __attribute__((packed)) csr_t; + +#define DMA_DESCRIPTOR_BUFFER_SIZE (32U) +#define DMA_DESCRIPTOR_BUFFER_ALIGN_SIZE (4U) +AT_NONCACHEABLE_SECTION_ALIGN(static uint32_t sdcard_adma_descriptor_table[DMA_DESCRIPTOR_BUFFER_SIZE], DMA_DESCRIPTOR_BUFFER_ALIGN_SIZE); + +#if defined MICROPY_USDHC1 && USDHC1_AVAIL +const mimxrt_sdcard_obj_pins_t mimxrt_sdcard_1_obj_pins = MICROPY_USDHC1; +#endif + +#if defined MICROPY_USDHC2 && USDHC2_AVAIL +const mimxrt_sdcard_obj_pins_t mimxrt_sdcard_2_obj_pins = MICROPY_USDHC2; +#endif + +#if defined MICROPY_USDHC1 && USDHC1_AVAIL +mimxrt_sdcard_status_obj_t sdcard_usdhc1_state = {.initialized = false, .inserted = false}; +#endif +#if defined MICROPY_USDHC2 && USDHC2_AVAIL +mimxrt_sdcard_status_obj_t sdcard_usdhc2_state = {.initialized = false, .inserted = false}; +#endif + +mimxrt_sdcard_obj_t mimxrt_sdcard_objs[] = +{ + #if defined MICROPY_USDHC1 && USDHC1_AVAIL + { + .base.type = &machine_sdcard_type, + .usdhc_inst = USDHC1, + .state = &sdcard_usdhc1_state, + .rca = 0x0UL, + .block_len = SDCARD_DEFAULT_BLOCK_SIZE, + .block_count = 0UL, + .pins = &mimxrt_sdcard_1_obj_pins, + }, + #endif + #if defined MICROPY_USDHC2 && USDHC2_AVAIL + { + .base.type = &machine_sdcard_type, + .usdhc_inst = USDHC2, + .state = &sdcard_usdhc2_state, + .rca = 0x0UL, + .block_len = SDCARD_DEFAULT_BLOCK_SIZE, + .block_count = 0UL, + .pins = &mimxrt_sdcard_2_obj_pins, + }; + #endif +}; + +volatile status_t sdcard_transfer_status; +volatile bool sdcard_transfer_done; + +// --- +// Local function declarations +// --- +static status_t sdcard_transfer_blocking(USDHC_Type *base, + usdhc_handle_t *handle, + usdhc_transfer_t *transfer, + uint32_t timeout_ms); +static void sdcard_decode_csd(mimxrt_sdcard_obj_t *sdcard, csd_t *csd); +static bool sdcard_reset(mimxrt_sdcard_obj_t *card); +static inline void sdcard_init_pin(const machine_pin_obj_t *pin, uint8_t af_idx, uint32_t config_value); + +// SD Card interrupt callbacks +void sdcard_card_inserted_callback(USDHC_Type *base, void *userData); +void sdcard_card_removed_callback(USDHC_Type *base, void *userData); +void sdcard_transfer_complete_callback(USDHC_Type *base, usdhc_handle_t *handle, status_t status, void *userData); +void sdcard_dummy_callback(USDHC_Type *base, void *userData); + +// SD Card commmands +static bool sdcard_cmd_go_idle_state(mimxrt_sdcard_obj_t *card); +static bool sdcard_cmd_oper_cond(mimxrt_sdcard_obj_t *card); +static bool sdcard_cmd_app_cmd(mimxrt_sdcard_obj_t *card); +static bool sdcard_cmd_sd_app_op_cond(mimxrt_sdcard_obj_t *card, uint32_t argument); +static bool sdcard_cmd_all_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid); +static bool sdcard_cmd_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid); +static bool sdcard_cmd_set_rel_add(mimxrt_sdcard_obj_t *card); +static bool sdcard_cmd_send_csd(mimxrt_sdcard_obj_t *card, csd_t *csd); +static bool sdcard_cmd_select_card(mimxrt_sdcard_obj_t *sdcard); +static bool sdcard_cmd_set_blocklen(mimxrt_sdcard_obj_t *sdcard); +static bool sdcard_cmd_set_bus_width(mimxrt_sdcard_obj_t *sdcard, uint8_t bus_width); + +void sdcard_card_inserted_callback(USDHC_Type *base, void *userData) { + #if defined MICROPY_USDHC1 && USDHC1_AVAIL + if (base == USDHC1) { + sdcard_usdhc1_state.inserted = true; + } + #endif + #if defined MICROPY_USDHC2 && USDHC2_AVAIL + if (base == USDHC2) { + sdcard_usdhc2_state.inserted = true; + + } + #endif + + USDHC_ClearInterruptStatusFlags(base, kUSDHC_CardInsertionFlag); +} + +void sdcard_card_removed_callback(USDHC_Type *base, void *userData) { + #if defined MICROPY_USDHC1 && USDHC1_AVAIL + if (base == USDHC1) { + sdcard_usdhc1_state.inserted = false; + sdcard_usdhc1_state.initialized = false; + } + #endif + #if defined MICROPY_USDHC2 && USDHC2_AVAIL + if (base == USDHC2) { + sdcard_usdhc2_state.inserted = false; + sdcard_usdhc2_state.initialized = false; + } + #endif + + USDHC_ClearInterruptStatusFlags(base, kUSDHC_CardRemovalFlag); +} + +void sdcard_transfer_complete_callback(USDHC_Type *base, usdhc_handle_t *handle, status_t status, void *userData) { + sdcard_transfer_status = status; + sdcard_transfer_done = true; + USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandCompleteFlag | kUSDHC_DataCompleteFlag); +} + +void sdcard_dummy_callback(USDHC_Type *base, void *userData) { + return; +} + +static status_t sdcard_transfer_blocking(USDHC_Type *base, usdhc_handle_t *handle, usdhc_transfer_t *transfer, uint32_t timeout_ms) { + uint32_t retry_ctr = 0UL; + status_t status; + + usdhc_adma_config_t dma_config; + + (void)memset(&dma_config, 0, sizeof(usdhc_adma_config_t)); + dma_config.dmaMode = kUSDHC_DmaModeAdma2; + dma_config.burstLen = kUSDHC_EnBurstLenForINCR; + dma_config.admaTable = sdcard_adma_descriptor_table; + dma_config.admaTableWords = DMA_DESCRIPTOR_BUFFER_SIZE; + + do { + status = USDHC_TransferNonBlocking(base, handle, &dma_config, transfer); + retry_ctr++; + } while (!(status == kStatus_Success) && (retry_ctr < 1000000UL)); + + if (status == kStatus_Success) { + for (int i = 0; i < timeout_ms * 100; i++) { + if ((sdcard_transfer_done == true) && (sdcard_transfer_status == kStatus_Success)) { + sdcard_transfer_done = false; + return kStatus_Success; + } + ticks_delay_us64(10); + } + return kStatus_Timeout; + } else { + return status; + } +} + +static void sdcard_decode_csd(mimxrt_sdcard_obj_t *card, csd_t *csd) { + uint8_t csd_structure = 0x3 & (csd->data[3] >> 30); + uint8_t read_bl_len; + uint32_t c_size; + uint8_t c_size_mult; + + switch (csd_structure) + { + case 0: { + read_bl_len = 0xF & (csd->data[2] >> 16); + c_size = ((0x3FF & csd->data[2]) << 30) | (0x3 & (csd->data[1] >> 30)); + c_size_mult = 0x7 & (csd->data[1] >> 15); + + card->block_len = (1U << (read_bl_len)); + card->block_count = ((c_size + 1U) << (c_size_mult + 2U)); + + if (card->block_len != SDCARD_DEFAULT_BLOCK_SIZE) { + card->block_count = (card->block_count * card->block_len); + card->block_len = SDCARD_DEFAULT_BLOCK_SIZE; + card->block_count = (card->block_count / card->block_len); + } + break; + } + case 1: { + c_size = ((0x3F & csd->data[2]) << 16) | (0xFFFF & (csd->data[1] >> 16)); + + card->block_len = 512UL; + card->block_count = (uint32_t)(((uint64_t)(c_size + 1U) * (uint64_t)1024UL)); + break; + } + case 2: { + c_size = ((0xFF & csd->data[2]) << 16) | (0xFFFF & (csd->data[1] >> 16)); + + card->block_len = 512UL; + card->block_count = (uint32_t)(((uint64_t)(c_size + 1U) * (uint64_t)1024UL)); + break; + } + default: { + break; + } + } +} + +static bool sdcard_cmd_go_idle_state(mimxrt_sdcard_obj_t *card) { + status_t status; + usdhc_command_t command = { + .index = SDCARD_CMD_GO_IDLE_STATE, + .argument = 0UL, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeNone, + }; + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_oper_cond(mimxrt_sdcard_obj_t *card) { + status_t status; + usdhc_command_t command = { + .index = SDCARD_CMD_SEND_IF_COND, + .argument = 0x000001AAU, // 2.7-3.3V range and 0xAA check pattern + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR7, + }; + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + card->oper_cond = command.response[0]; + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_app_cmd(mimxrt_sdcard_obj_t *card) { + status_t status; + usdhc_command_t command = { + .index = SDCARD_CMD_APP_CMD, + .argument = (card->rca << 16), + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR1, + }; + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + card->status = command.response[0]; + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_sd_app_op_cond(mimxrt_sdcard_obj_t *card, uint32_t argument) { + if (!sdcard_cmd_app_cmd(card)) { + return false; + } + + status_t status; + usdhc_command_t command = { + .index = SDCARD_ACMD_SD_SEND_OP_COND, + .argument = argument, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR3, + }; + + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + card->oper_cond = command.response[0]; + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_all_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid) { + status_t status; + usdhc_command_t command = { + .index = SDCARD_CMD_ALL_SEND_CID, + .argument = 0UL, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR2, + }; + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + cid->mdt = (uint16_t)((command.response[0] & 0xFFF00U) >> 8U); + cid->psn = (uint32_t)(((command.response[1] & 0xFFFFFFU) << 8U) | ((command.response[0] & 0xFF000000U) >> 24U)); + cid->prv = (uint8_t)((command.response[1] & 0xFF000000U) >> 24U); + cid->pnm[0] = (char)(command.response[2] & 0xFFU); + cid->pnm[1] = (char)((command.response[2] & 0xFF00U) >> 8U); + cid->pnm[2] = (char)((command.response[2] & 0xFF0000U) >> 16U); + cid->pnm[3] = (char)((command.response[2] & 0xFF000000U) >> 24U); + cid->pnm[4] = (char)(command.response[3] & 0xFFU); + cid->pnm[5] = '\0'; + cid->oid = (uint16_t)((command.response[3] & 0xFFFF00U) >> 8U); + cid->mid = (uint8_t)((command.response[3] & 0xFF000000U) >> 24U); + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_send_cid(mimxrt_sdcard_obj_t *card, cid_t *cid) { + status_t status; + usdhc_command_t command = { + .index = SDCARD_CMD_SEND_CID, + .argument = (card->rca << 16), + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR2, + }; + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + cid->mdt = (uint16_t)((command.response[0] & 0xFFF00U) >> 8U); + cid->psn = (uint32_t)(((command.response[1] & 0xFFFFFFU) << 8U) | ((command.response[0] & 0xFF000000U) >> 24U)); + cid->prv = (uint8_t)((command.response[1] & 0xFF000000U) >> 24U); + cid->pnm[0] = (char)(command.response[2] & 0xFFU); + cid->pnm[1] = (char)((command.response[2] & 0xFF00U) >> 8U); + cid->pnm[2] = (char)((command.response[2] & 0xFF0000U) >> 16U); + cid->pnm[3] = (char)((command.response[2] & 0xFF000000U) >> 24U); + cid->pnm[4] = (char)(command.response[3] & 0xFFU); + cid->pnm[5] = '\0'; + cid->oid = (uint16_t)((command.response[3] & 0xFFFF00U) >> 8U); + cid->mid = (uint8_t)((command.response[3] & 0xFF000000U) >> 24U); + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_set_rel_add(mimxrt_sdcard_obj_t *card) { + status_t status; + usdhc_command_t command = { + .index = SDCARD_CMD_SEND_REL_ADDR, + .argument = 0UL, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR6, + }; + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + card->rca = 0xFFFFFFFF & (command.response[0] >> 16); + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_send_csd(mimxrt_sdcard_obj_t *card, csd_t *csd) { + status_t status; + usdhc_command_t command = { + .index = SDCARD_CMD_SEND_CSD, + .argument = (card->rca << 16), + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR2, + }; + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + csd->data[0] = command.response[0]; + csd->data[1] = command.response[1]; + csd->data[2] = command.response[2]; + csd->data[3] = command.response[3]; + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_select_card(mimxrt_sdcard_obj_t *card) { + status_t status; + usdhc_command_t command = { + .index = SDCARD_CMD_SELECT_CARD, + .argument = (card->rca << 16), + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR1b, + .responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG, + }; + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + card->status = command.response[0]; + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_set_blocklen(mimxrt_sdcard_obj_t *card) { + status_t status; + usdhc_command_t command = { + .index = SDCARD_CMD_SET_BLOCKLENGTH, + .argument = card->block_len, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR1, + .responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG, + }; + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + card->status = command.response[0]; + return true; + } else { + return false; + } +} + +static bool sdcard_cmd_set_bus_width(mimxrt_sdcard_obj_t *card, usdhc_data_bus_width_t bus_width) { + if (!sdcard_cmd_app_cmd(card)) { + return false; + } + + status_t status; + usdhc_command_t command = { + .index = SDCARD_ACMD_SET_BUS_WIDTH, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR1, + }; + + if (bus_width == kUSDHC_DataBusWidth1Bit) { + command.argument = 0U; + } else if (bus_width == kUSDHC_DataBusWidth4Bit) { + command.argument = 2U; + } else { + return false; // Invalid argument + } + + usdhc_transfer_t transfer = { + .data = NULL, + .command = &command, + }; + + status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 250); + + if (status == kStatus_Success) { + card->status = command.response[0]; + return true; + } else { + return false; + } +} + +static bool sdcard_reset(mimxrt_sdcard_obj_t *card) { + card->block_len = SDCARD_DEFAULT_BLOCK_SIZE; + card->rca = 0UL; + card->block_count = 0UL; + card->status = 0UL; + card->oper_cond = 0UL; + card->state->initialized = false; + return USDHC_Reset(card->usdhc_inst, (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK), 2048); +} + +void sdcard_init(mimxrt_sdcard_obj_t *card, uint32_t base_clk) { + // Configure PFD0 of PLL2 (system PLL) fractional divider to 24 resulting in: + // with PFD0_clk = PLL2_clk * 18 / N + // PFD0_clk = 528MHz * 18 / 24 = 396MHz + CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U); + + #if defined MICROPY_USDHC1 && USDHC1_AVAIL + // Configure USDHC clock source and divider + CLOCK_SetDiv(kCLOCK_Usdhc1Div, 1U); // USDHC_input_clk = PFD0_clk / 2 = 198MHZ + CLOCK_SetMux(kCLOCK_Usdhc1Mux, 1U); // Select PFD0 as clock input for USDHC + #endif + + #if defined MICROPY_USDHC2 && USDHC2_AVAIL + // Configure USDHC clock source and divider + CLOCK_SetDiv(kCLOCK_Usdhc2Div, 1U); // USDHC_input_clk = PFD0_clk / 2 = 198MHZ + CLOCK_SetMux(kCLOCK_Usdhc2Mux, 1U); // Select PFD0 as clock input for USDHC + #endif + + // Initialize USDHC + const usdhc_config_t config = { + .endianMode = kUSDHC_EndianModeLittle, + .dataTimeout = 0xFU, + .readWatermarkLevel = 128U, + .writeWatermarkLevel = 128U, + }; + USDHC_Init(card->usdhc_inst, &config); + + (void)sdcard_reset(card); + card->base_clk = base_clk; + + usdhc_transfer_callback_t callbacks = { + .CardInserted = sdcard_card_inserted_callback, + .CardRemoved = sdcard_card_removed_callback, + .SdioInterrupt = sdcard_dummy_callback, + .BlockGap = sdcard_dummy_callback, + .TransferComplete = sdcard_transfer_complete_callback, + .ReTuning = sdcard_dummy_callback, + }; + + USDHC_TransferCreateHandle(card->usdhc_inst, &card->handle, &callbacks, NULL); +} + +void sdcard_deinit(mimxrt_sdcard_obj_t *card) { + sdcard_power_off(card); + USDHC_Deinit(card->usdhc_inst); +} + +static inline void sdcard_init_pin(const machine_pin_obj_t *pin, uint8_t af_idx, uint32_t config_value) { + machine_pin_af_obj_t af = pin->af_list[af_idx]; + + IOMUXC_SetPinMux(pin->muxRegister, af.af_mode, af.input_register, af.input_daisy, pin->configRegister, 0U); + IOMUXC_SetPinConfig(pin->muxRegister, af.af_mode, af.input_register, af.input_daisy, pin->configRegister, config_value); +} + +void sdcard_init_pins(mimxrt_sdcard_obj_t *card) { + // speed and strength optimized for clock frequency < 100MHz + uint32_t speed = 1U; + uint32_t strength = 7U; + const mimxrt_sdcard_obj_pins_t *pins = card->pins; + + uint32_t default_config = IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | + IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | + IOMUXC_SW_PAD_CTL_PAD_PUS(1) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength); + uint32_t no_cd_config = IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | + IOMUXC_SW_PAD_CTL_PAD_SRE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | + IOMUXC_SW_PAD_CTL_PAD_PUE_MASK | + IOMUXC_SW_PAD_CTL_PAD_HYS_MASK | + IOMUXC_SW_PAD_CTL_PAD_PUS(0) | + IOMUXC_SW_PAD_CTL_PAD_DSE(strength); + + sdcard_init_pin(card->pins->clk.pin, card->pins->clk.af_idx, default_config); // USDHC1_CLK + sdcard_init_pin(card->pins->cmd.pin, card->pins->cmd.af_idx, default_config); // USDHC1_CMD + sdcard_init_pin(card->pins->data0.pin, card->pins->data0.af_idx, default_config); // USDHC1_DATA0 + sdcard_init_pin(card->pins->data1.pin, card->pins->data1.af_idx, default_config); // USDHC1_DATA1 + sdcard_init_pin(card->pins->data2.pin, card->pins->data2.af_idx, default_config); // USDHC1_DATA2 + + if (pins->cd_b.pin) { + sdcard_init_pin(card->pins->data3.pin, card->pins->data3.af_idx, default_config); // USDHC1_DATA3 + sdcard_init_pin(card->pins->cd_b.pin, card->pins->cd_b.af_idx, default_config); // USDHC1_CD_B + USDHC_CardDetectByData3(card->usdhc_inst, false); + } else { + sdcard_init_pin(card->pins->data3.pin, card->pins->data3.af_idx, no_cd_config); // USDHC1_DATA3 + USDHC_CardDetectByData3(card->usdhc_inst, true); + } +} + +bool sdcard_read(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num, uint32_t block_count) { + if (!card->state->initialized) { + return false; + } + + usdhc_data_t data = { + .enableAutoCommand12 = true, + .enableAutoCommand23 = false, + .enableIgnoreError = false, + .dataType = kUSDHC_TransferDataNormal, + .blockSize = card->block_len, + .blockCount = block_count, + .rxData = (uint32_t *)buffer, + .txData = NULL, + }; + + usdhc_command_t command = { + .index = (block_count == 1U) ? (uint32_t)SDCARD_CMD_READ_SINGLE_BLOCK : (uint32_t)SDCARD_CMD_READ_MULTIPLE_BLOCK, + .argument = block_num, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR1, + .responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG, + }; + + usdhc_transfer_t transfer = { + .data = &data, + .command = &command, + }; + + status_t status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 500); + + if (status == kStatus_Success) { + card->status = command.response[0]; + return true; + } else { + return false; + } +} + +bool sdcard_write(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num, uint32_t block_count) { + if (!card->state->initialized) { + return false; + } + + usdhc_data_t data = { + .enableAutoCommand12 = true, + .enableAutoCommand23 = false, + .enableIgnoreError = false, + .dataType = kUSDHC_TransferDataNormal, + .blockSize = card->block_len, + .blockCount = block_count, + .rxData = NULL, + .txData = (uint32_t *)buffer, + }; + + usdhc_command_t command = { + .index = (block_count == 1U) ? (uint32_t)SDCARD_CMD_WRITE_SINGLE_BLOCK : (uint32_t)SDCARD_CMD_WRITE_MULTIPLE_BLOCK, + .argument = block_num, + .type = kCARD_CommandTypeNormal, + .responseType = kCARD_ResponseTypeR1, + .responseErrorFlags = SDMMC_R1_ALL_ERROR_FLAG, + }; + + usdhc_transfer_t transfer = { + .data = &data, + .command = &command, + }; + + status_t status = sdcard_transfer_blocking(card->usdhc_inst, &card->handle, &transfer, 500); + + if (status == kStatus_Success) { + card->status = command.response[0]; + return true; + } else { + return false; + } +} + +bool sdcard_set_active(mimxrt_sdcard_obj_t *card) { + return USDHC_SetCardActive(card->usdhc_inst, 8192); +} + +bool sdcard_probe_bus_voltage(mimxrt_sdcard_obj_t *card) { + bool valid_voltage = false; + uint32_t count = 0UL; + bool status = false; + + // Perform voltage validation + while ((count < SDCARD_MAX_VOLT_TRIAL) && (valid_voltage == false)) { + status = sdcard_cmd_sd_app_op_cond(card, (uint32_t)(SDCARD_VOLTAGE_WINDOW_SD | + SDCARD_HIGH_CAPACITY | + SDCARD_SWITCH_1_8V_CAPACITY)); + if (status == false) { + return false; + } + + /* Get operating voltage*/ + valid_voltage = (((card->oper_cond >> 31U) == 1U) ? true : false); + count++; + ticks_delay_us64(1000); + } + + if (count >= SDCARD_MAX_VOLT_TRIAL) { + return false; + } else { + return true; + } +} + +bool sdcard_power_on(mimxrt_sdcard_obj_t *card) { + bool status = false; + + // Check if card is already initialized and powered on + if (card->state->initialized) { + return true; + } + + USDHC_SetDataBusWidth(card->usdhc_inst, kUSDHC_DataBusWidth1Bit); + card->bus_clk = USDHC_SetSdClock(card->usdhc_inst, card->base_clk, SDCARD_CLOCK_400KHZ); + + // Start initialization process + status = sdcard_reset(card); + if (!status) { + return false; + } + + status = sdcard_set_active(card); + if (!status) { + return false; + } + + status = sdcard_cmd_go_idle_state(card); + if (!status) { + return false; + } + + status = sdcard_cmd_oper_cond(card); + if (!status) { + return false; + } + + status = sdcard_probe_bus_voltage(card); + if (!status) { + return false; + } + + // === + // Ready State + // === + cid_t cid_all; + status = sdcard_cmd_all_send_cid(card, &cid_all); + if (!status) { + return false; + } + + // === + // Identification State + // === + status = sdcard_cmd_set_rel_add(card); + if (!status) { + return false; + } + + // === + // Standby State + // === + card->bus_clk = USDHC_SetSdClock(card->usdhc_inst, card->base_clk, SDCARD_CLOCK_50MHZ); + + csd_t csd; + status = sdcard_cmd_send_csd(card, &csd); + if (!status) { + return false; + } + sdcard_decode_csd(card, &csd); + + cid_t cid; + status = sdcard_cmd_send_cid(card, &cid); + if (!status) { + return false; + } + + // === + // Transfer State + // === + status = sdcard_cmd_select_card(card); + if (!status) { + return false; + } + + status = sdcard_cmd_set_blocklen(card); + if (!status) { + return false; + } + + status = sdcard_cmd_set_bus_width(card, kUSDHC_DataBusWidth4Bit); + if (!status) { + return false; + } + USDHC_SetDataBusWidth(card->usdhc_inst, kUSDHC_DataBusWidth4Bit); + + + status = sdcard_cmd_set_blocklen(card); + if (!status) { + return false; + } + + // Finialize initialization + card->state->initialized = true; + return true; +} + +bool sdcard_power_off(mimxrt_sdcard_obj_t *card) { + (void)sdcard_cmd_go_idle_state(card); + + // Reset card bus clock + USDHC_SetDataBusWidth(card->usdhc_inst, kUSDHC_DataBusWidth1Bit); + card->bus_clk = USDHC_SetSdClock(card->usdhc_inst, card->base_clk, SDCARD_CLOCK_400KHZ); + + (void)sdcard_reset(card); + return true; +} + +bool sdcard_detect(mimxrt_sdcard_obj_t *card) { + bool detect = false; + + #if defined MICROPY_USDHC1 && USDHC1_AVAIL + if ((card->usdhc_inst == USDHC1) && (sdcard_usdhc1_state.inserted == true)) { + return true; + } + #endif + #if defined MICROPY_USDHC2 && USDHC2_AVAIL + if ((card->usdhc_inst == USDHC2) && (sdcard_usdhc2_state.inserted == true)) { + return true; + } + #endif + + if (card->pins->cd_b.pin) { + detect = USDHC_DetectCardInsert(card->usdhc_inst); + } else { + USDHC_CardDetectByData3(card->usdhc_inst, true); + detect = (USDHC_GetPresentStatusFlags(card->usdhc_inst) & USDHC_PRES_STATE_DLSL(8)) != 0; + } + + // Update card state when detected via pin state + #if defined MICROPY_USDHC1 && USDHC1_AVAIL + if (card->usdhc_inst == USDHC1) { + sdcard_usdhc1_state.inserted = detect; + sdcard_usdhc1_state.initialized = detect ? sdcard_usdhc1_state.initialized : false; + } + #endif + #if defined MICROPY_USDHC2 && USDHC2_AVAIL + if (card->usdhc_inst == USDHC2) { + sdcard_usdhc2_state.inserted = detect; + sdcard_usdhc2_state.initialized = detect ? sdcard_usdhc2_state.initialized : false; + } + #endif + + return detect; +} + +#endif // MICROPY_PY_MACHINE_SDCARD diff --git a/ports/mimxrt/sdcard.h b/ports/mimxrt/sdcard.h new file mode 100644 index 000000000..9219a4230 --- /dev/null +++ b/ports/mimxrt/sdcard.h @@ -0,0 +1,111 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Philipp Ebensberger + * + * 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_MIMXRT_SDCARD_H +#define MICROPY_INCLUDED_MIMXRT_SDCARD_H + +#include "modmachine.h" +#include "pin.h" +#include "fsl_usdhc.h" + +// --- +// SD Card public defines +// --- +#define SDCARD_DEFAULT_BLOCK_SIZE (512U) +#define SDCARD_CLOCK_400KHZ (400000U) +#define SDCARD_CLOCK_25MHZ (25000000U) +#define SDCARD_CLOCK_50MHZ (50000000U) + +typedef struct _mimxrt_sdcard_pin_t { + const machine_pin_obj_t *pin; + uint8_t af_idx; +} mimxrt_sdcard_pin_t; + +typedef struct _mimxrt_sdcard_obj_pins_t { + mimxrt_sdcard_pin_t cmd; + mimxrt_sdcard_pin_t clk; + mimxrt_sdcard_pin_t cd_b; + mimxrt_sdcard_pin_t data0; + mimxrt_sdcard_pin_t data1; + mimxrt_sdcard_pin_t data2; + mimxrt_sdcard_pin_t data3; +} mimxrt_sdcard_obj_pins_t; + +typedef volatile struct _mimxrt_sdcard_status_obj_t { + bool initialized; + bool inserted; +} mimxrt_sdcard_status_obj_t; + +typedef struct _mimxrt_sdcard_obj_t { + mp_obj_base_t base; + USDHC_Type *usdhc_inst; + usdhc_handle_t handle; + mimxrt_sdcard_status_obj_t *state; + uint16_t block_len; + uint32_t base_clk; + uint32_t bus_clk; + uint32_t rca; + uint32_t block_count; + uint32_t status; + uint32_t oper_cond; + const mimxrt_sdcard_obj_pins_t *pins; +} mimxrt_sdcard_obj_t; + +// --- +// SD Card object instances +// --- +#if MICROPY_PY_MACHINE_SDCARD && (defined MICROPY_USDHC1 || defined MICROPY_USDHC2) +enum { + #if defined MICROPY_USDHC1 && USDHC1_AVAIL + SDCARD_OBJ_USDHC1_IDX, + #endif + #if defined MICROPY_USDHC2 && USDHC2_AVAIL + SDCARD_OBJ_USDHC2_IDX, + #endif + SDCARD_OBJ_USDHC_N +}; +#endif +extern mimxrt_sdcard_obj_t mimxrt_sdcard_objs[SDCARD_OBJ_USDHC_N]; + +// --- +// SD Card functions +// --- +void sdcard_init(mimxrt_sdcard_obj_t *card, uint32_t base_clk); +void sdcard_deinit(mimxrt_sdcard_obj_t *card); +void sdcard_init_pins(mimxrt_sdcard_obj_t *card); +bool sdcard_read(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num, uint32_t block_count); +bool sdcard_write(mimxrt_sdcard_obj_t *card, uint8_t *buffer, uint32_t block_num, uint32_t block_count); +bool sdcard_set_active(mimxrt_sdcard_obj_t *card); +bool sdcard_volt_validation(mimxrt_sdcard_obj_t *card); +bool sdcard_power_on(mimxrt_sdcard_obj_t *self); +bool sdcard_power_off(mimxrt_sdcard_obj_t *self); +bool sdcard_detect(mimxrt_sdcard_obj_t *self); + +static inline bool sdcard_state_initialized(mimxrt_sdcard_obj_t *card) { + return card->state->initialized; +} + +#endif // MICROPY_INCLUDED_MIMXRT_SDCARD_H diff --git a/ports/mimxrt/systick.c b/ports/mimxrt/systick.c new file mode 100644 index 000000000..086bf1670 --- /dev/null +++ b/ports/mimxrt/systick.c @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "systick.h" + +volatile uint32_t systick_ms = 0; + +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 = systick_ms + 1; + systick_ms = uw_tick; + + // 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); + } +} + +bool systick_has_passed(uint32_t start_tick, uint32_t delay_ms) { + return systick_ms - 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 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/mimxrt/systick.h b/ports/mimxrt/systick.h new file mode 100644 index 000000000..2638905cd --- /dev/null +++ b/ports/mimxrt/systick.h @@ -0,0 +1,60 @@ +/* + * 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. + */ +#ifndef MICROPY_INCLUDED_MIMXRT_SYSTICK_H +#define MICROPY_INCLUDED_MIMXRT_SYSTICK_H + +// 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 + #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP + SYSTICK_DISPATCH_LWIP, + #endif + SYSTICK_DISPATCH_MAX +}; + +#define SYSTICK_DISPATCH_NUM_SLOTS POW2_CEIL(SYSTICK_DISPATCH_MAX) + +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); + +#endif // MICROPY_INCLUDED_MIMXRT_SYSTICK_H diff --git a/ports/mimxrt/ticks.c b/ports/mimxrt/ticks.c index 676f81b30..0fc9babc0 100644 --- a/ports/mimxrt/ticks.c +++ b/ports/mimxrt/ticks.c @@ -56,6 +56,9 @@ void ticks_init(void) { NVIC_EnableIRQ(GPTx_IRQn); GPT_StartTimer(GPTx); + #ifdef NDEBUG + mp_hal_ticks_cpu_enable(); + #endif } void GPTx_IRQHandler(void) { @@ -128,9 +131,7 @@ void ticks_delay_us64(uint64_t us) { dt = 0xffffffff; } ticks_wake_after_us32((uint32_t)dt); - if (dt < 50) { - __WFE(); - } else { + if (dt > 50) { MICROPY_EVENT_POLL_HOOK } } diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile index 21e3fe3f7..fc3730e70 100644 --- a/ports/minimal/Makefile +++ b/ports/minimal/Makefile @@ -27,8 +27,8 @@ CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT) LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref --gc-sections else LD = gcc -CFLAGS = -m32 $(INC) -Wall -Werror -Wdouble-promotion -Wfloat-conversion -std=c99 $(COPT) -LDFLAGS = -m32 -Wl,-Map=$@.map,--cref -Wl,--gc-sections +CFLAGS = $(INC) -Wall -Werror -Wdouble-promotion -Wfloat-conversion -std=c99 $(COPT) +LDFLAGS = -Wl,-Map=$@.map,--cref -Wl,--gc-sections endif CSUPEROPT = -Os # save some code space diff --git a/ports/minimal/mpconfigport.h b/ports/minimal/mpconfigport.h index b34217f68..c9f399876 100644 --- a/ports/minimal/mpconfigport.h +++ b/ports/minimal/mpconfigport.h @@ -2,46 +2,22 @@ // options to control how MicroPython is built +// Use the minimal starting configuration (disables all optional features). +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_MINIMUM) + // 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 (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_COMP_CONST (0) -#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) -#define MICROPY_ENABLE_GC (1) -#define MICROPY_GC_ALLOC_THRESHOLD (0) -#define MICROPY_HELPER_REPL (1) -#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) -#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) -#define MICROPY_PY_ASYNC_AWAIT (0) -#define MICROPY_PY_ASSIGN_EXPR (0) -#define MICROPY_PY_BUILTINS_BYTEARRAY (0) -#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (0) -#define MICROPY_PY_BUILTINS_ENUMERATE (0) -#define MICROPY_PY_BUILTINS_FILTER (0) -#define MICROPY_PY_BUILTINS_REVERSED (0) -#define MICROPY_PY_BUILTINS_SET (0) -#define MICROPY_PY_BUILTINS_SLICE (0) -#define MICROPY_PY_BUILTINS_PROPERTY (0) -#define MICROPY_PY_BUILTINS_MIN_MAX (0) -#define MICROPY_PY_BUILTINS_STR_COUNT (0) -#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0) -#define MICROPY_PY___FILE__ (0) -#define MICROPY_PY_GC (0) -#define MICROPY_PY_ARRAY (0) -#define MICROPY_PY_ATTRTUPLE (0) -#define MICROPY_PY_COLLECTIONS (0) -#define MICROPY_PY_IO (0) -#define MICROPY_PY_STRUCT (0) -#define MICROPY_PY_SYS (0) -#define MICROPY_MODULE_FROZEN_MPY (1) -#define MICROPY_CPYTHON_COMPAT (0) -#define MICROPY_MODULE_GETATTR (0) +#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool +#define MICROPY_ENABLE_GC (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_MODULE_FROZEN_MPY (1) +#define MICROPY_ENABLE_EXTERNAL_IMPORT (1) + +#define MICROPY_ALLOC_PATH_MAX (256) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16) // type definitions for the specific machine diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index a8a522827..c32e09d2c 100644 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -340,11 +340,6 @@ DRIVERS_SRC_C += $(addprefix modules/,\ SRC_C += \ device/startup_$(MCU_SUB_VARIANT).c \ -ifneq ($(FROZEN_MPY_DIR),) -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 @@ -430,19 +425,19 @@ else ifeq ($(FLASHER), bmp) BMP_PORT ?= /dev/ttyACM0 deploy: $(BUILD)/$(OUTPUT_FILENAME).elf - $(Q)$(GDB) \ + $(Q)$(GDB) -nx --batch \ -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 'compare-sections' \ -ex 'kill' \ - -ex 'quit' \ $< sd: $(BUILD)/$(OUTPUT_FILENAME).elf - $(Q)$(GDB) \ + $(Q)$(GDB) -nx --batch \ -ex 'target extended-remote $(BMP_PORT)' \ -ex 'monitor tpwr enable' \ -ex 'monitor swdp_scan' \ @@ -450,10 +445,11 @@ sd: $(BUILD)/$(OUTPUT_FILENAME).elf -ex 'set mem inaccessible-by-default off' \ -ex 'monitor erase_mass' \ -ex 'load' \ + -ex 'compare-sections' \ -ex 'file $(SOFTDEV_HEX)' \ -ex 'load' \ + -ex 'compare-sections' \ -ex 'kill' \ - -ex 'quit' \ $< else ifeq ($(FLASHER), openocd) @@ -541,17 +537,10 @@ GEN_PINS_QSTR = $(BUILD)/pins_qstr.h GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h GEN_PINS_AF_PY = $(BUILD)/pins_af.py -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_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). +ifneq ($(FROZEN_MANIFEST),) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +CFLAGS += -DMICROPY_MODULE_FROZEN_STR endif $(PY_BUILD)/nlr%.o: CFLAGS += -Os -fno-lto diff --git a/ports/nrf/README.md b/ports/nrf/README.md index aa8968ff9..a833f0f17 100644 --- a/ports/nrf/README.md +++ b/ports/nrf/README.md @@ -96,20 +96,6 @@ The **make sd** will trigger a flash of the bluetooth stack before that applicat Note: further tuning of features to include in bluetooth or even setting up the device to use REPL over Bluetooth can be configured in the `bluetooth_conf.h`. -## Compile with frozen modules - -Frozen modules are Python modules compiled to bytecode and added to the firmware -image, as part of MicroPython. They can be imported as usual, using the `import` -statement. The advantage is that frozen modules use a lot less RAM as the -bytecode is stored in flash, not in RAM like when importing from a filesystem. -Also, frozen modules are available even when no filesystem is present to import -from. - -To use frozen modules, put them in a directory (e.g. `freeze/`) and supply -`make` with the given directory. For example: - - make BOARD=pca10040 FROZEN_MPY_DIR=freeze - ## Compile with freeze manifest Freeze manifests can be used by definining `FROZEN_MANIFEST` pointing to a diff --git a/ports/nrf/boards/actinius_icarus/board.json b/ports/nrf/boards/actinius_icarus/board.json new file mode 100644 index 000000000..c1d9f1c4e --- /dev/null +++ b/ports/nrf/boards/actinius_icarus/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "icarus-v1.4-front-shadow-p-800.jpg" + ], + "mcu": "nrf91", + "product": "actinius_icarus", + "thumbnail": "", + "url": "https://www.actinius.com/icarus", + "vendor": "Actinius" +} diff --git a/ports/nrf/boards/arduino_primo/board.json b/ports/nrf/boards/arduino_primo/board.json new file mode 100644 index 000000000..d16ce1c34 --- /dev/null +++ b/ports/nrf/boards/arduino_primo/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "arduino_primo.jpg" + ], + "mcu": "nrf52", + "product": "arduino_primo", + "thumbnail": "", + "url": "", + "vendor": "" +} diff --git a/ports/nrf/boards/blueio_tag_evim/board.json b/ports/nrf/boards/blueio_tag_evim/board.json new file mode 100644 index 000000000..5b6e5747d --- /dev/null +++ b/ports/nrf/boards/blueio_tag_evim/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "blyst-nano-mod-4_jpg_project-body.jpg" + ], + "mcu": "nrf52", + "product": "blueio_tag_evim", + "thumbnail": "", + "url": "https://www.i-syst.com/index.php/products/blyst-nano", + "vendor": "I-SYST" +} diff --git a/ports/nrf/boards/deploy.md b/ports/nrf/boards/deploy.md new file mode 100644 index 000000000..e69de29bb diff --git a/ports/nrf/boards/dvk_bl652/board.json b/ports/nrf/boards/dvk_bl652/board.json new file mode 100644 index 000000000..5c9cfad26 --- /dev/null +++ b/ports/nrf/boards/dvk_bl652/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "BL652-SA_JPG-500.jpg" + ], + "mcu": "nrf52", + "product": "dvk_bl652", + "thumbnail": "", + "url": "https://www.lairdconnect.com/wireless-modules/bluetooth-modules/bluetooth-5-modules/bl652-series-bluetooth-v5-nfc-module", + "vendor": "Laird Connectivity" +} diff --git a/ports/nrf/boards/evk_nina_b1/board.json b/ports/nrf/boards/evk_nina_b1/board.json new file mode 100644 index 000000000..657b0fa06 --- /dev/null +++ b/ports/nrf/boards/evk_nina_b1/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "https://www.u-blox.com/sites/default/files/EVK-NINA-B1_UserGuide_%28UBX-15028120%29.pdf", + "features": [], + "images": [ + "EVK-NINA-B1_.jpg" + ], + "mcu": "nrf52", + "product": "evk_nina_b1", + "thumbnail": "", + "url": "https://www.u-blox.com/en/product/evk-nina-b1", + "vendor": "u-blox" +} diff --git a/ports/nrf/boards/evk_nina_b3/board.json b/ports/nrf/boards/evk_nina_b3/board.json new file mode 100644 index 000000000..54e3dc358 --- /dev/null +++ b/ports/nrf/boards/evk_nina_b3/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "EVK-NINA-B3-top.jpg" + ], + "mcu": "nrf52", + "product": "evk_nina_b3", + "thumbnail": "", + "url": "https://www.u-blox.com/en/product/evk-nina-b3", + "vendor": "u-blox" +} diff --git a/ports/nrf/boards/feather52/board.json b/ports/nrf/boards/feather52/board.json new file mode 100644 index 000000000..344b880ba --- /dev/null +++ b/ports/nrf/boards/feather52/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "4062-02.jpg" + ], + "mcu": "nrf52", + "product": "Feather nRF52840 Express", + "thumbnail": "", + "url": "https://www.adafruit.com/product/4062", + "vendor": "Adafruit" +} diff --git a/ports/nrf/boards/ibk_blyst_nano/board.json b/ports/nrf/boards/ibk_blyst_nano/board.json new file mode 100644 index 000000000..562c33607 --- /dev/null +++ b/ports/nrf/boards/ibk_blyst_nano/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "blyst-nano-fingertip-close_jpg_content-body-gallery.jpg" + ], + "mcu": "nrf52", + "product": "ibk_blyst_nano", + "thumbnail": "", + "url": "https://www.i-syst.com/products/blyst-nano", + "vendor": "I-SYST" +} diff --git a/ports/nrf/boards/idk_blyst_nano/board.json b/ports/nrf/boards/idk_blyst_nano/board.json new file mode 100644 index 000000000..199721698 --- /dev/null +++ b/ports/nrf/boards/idk_blyst_nano/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "blyst-nano-fingertip-close_jpg_content-body-gallery.jpg" + ], + "mcu": "nrf52", + "product": "idk_blyst_nano", + "thumbnail": "", + "url": "https://www.i-syst.com/products/blyst-nano", + "vendor": "I-SYST" +} diff --git a/ports/nrf/boards/microbit/board.json b/ports/nrf/boards/microbit/board.json new file mode 100644 index 000000000..872727bb9 --- /dev/null +++ b/ports/nrf/boards/microbit/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "AF-3362-1.jpg" + ], + "mcu": "nrf51", + "product": "micro:bit v1", + "thumbnail": "", + "url": "https://microbit.org/", + "vendor": "BBC" +} diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json b/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json new file mode 100644 index 000000000..853c37571 --- /dev/null +++ b/ports/nrf/boards/nrf52840-mdk-usb-dongle/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "dongle_pcba_case.jpg" + ], + "mcu": "nrf52", + "product": "nrf52840-mdk-usb-dongle", + "thumbnail": "", + "url": "https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle", + "vendor": "" +} diff --git a/ports/nrf/boards/particle_xenon/board.json b/ports/nrf/boards/particle_xenon/board.json new file mode 100644 index 000000000..1f6b90b75 --- /dev/null +++ b/ports/nrf/boards/particle_xenon/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "xenon-top.jpg" + ], + "mcu": "nrf52", + "product": "Xenon", + "thumbnail": "", + "url": "https://docs.particle.io/xenon/", + "vendor": "Particle" +} diff --git a/ports/nrf/boards/pca10000/board.json b/ports/nrf/boards/pca10000/board.json new file mode 100644 index 000000000..1f6e73869 --- /dev/null +++ b/ports/nrf/boards/pca10000/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nRF51-Dongle.jpg" + ], + "mcu": "nrf51", + "product": "pca10000", + "thumbnail": "", + "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF51-Dongle", + "vendor": "Nordic Semiconductor" +} diff --git a/ports/nrf/boards/pca10001/board.json b/ports/nrf/boards/pca10001/board.json new file mode 100644 index 000000000..ca1a42df7 --- /dev/null +++ b/ports/nrf/boards/pca10001/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nRF51-DK.jpg" + ], + "mcu": "nrf51", + "product": "pca10001", + "thumbnail": "", + "url": "https://www.nordicsemi.com/Products/Development-hardware/nrf51-dk", + "vendor": "Nordic Semiconductor" +} diff --git a/ports/nrf/boards/pca10028/board.json b/ports/nrf/boards/pca10028/board.json new file mode 100644 index 000000000..f80cea469 --- /dev/null +++ b/ports/nrf/boards/pca10028/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nRF51-DK.jpg" + ], + "mcu": "nrf51", + "product": "pca10028", + "thumbnail": "", + "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF51-DK", + "vendor": "Nordic Semiconductor" +} diff --git a/ports/nrf/boards/pca10031/board.json b/ports/nrf/boards/pca10031/board.json new file mode 100644 index 000000000..fb7c774ca --- /dev/null +++ b/ports/nrf/boards/pca10031/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nRF51-Dongle.jpg" + ], + "mcu": "nrf51", + "product": "pca10031", + "thumbnail": "", + "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF51-Dongle", + "vendor": "Nordic Semiconductor" +} diff --git a/ports/nrf/boards/pca10040/board.json b/ports/nrf/boards/pca10040/board.json new file mode 100644 index 000000000..d1680e53a --- /dev/null +++ b/ports/nrf/boards/pca10040/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nRF52-DK-prod-page.jpg" + ], + "mcu": "nrf52", + "product": "pca10040", + "thumbnail": "", + "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF52-DK", + "vendor": "Nordic Semiconductor" +} diff --git a/ports/nrf/boards/pca10056/board.json b/ports/nrf/boards/pca10056/board.json new file mode 100644 index 000000000..763d8d824 --- /dev/null +++ b/ports/nrf/boards/pca10056/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nRF52840-DK-prod-page.jpg" + ], + "mcu": "nrf52", + "product": "pca10056", + "thumbnail": "", + "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF52840-DK", + "vendor": "Nordic Semiconductor" +} diff --git a/ports/nrf/boards/pca10059/board.json b/ports/nrf/boards/pca10059/board.json new file mode 100644 index 000000000..14bd8bf7e --- /dev/null +++ b/ports/nrf/boards/pca10059/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "pca10059.jpg" + ], + "mcu": "nrf52", + "product": "pca10059", + "thumbnail": "", + "url": "https://www.nordicsemi.com/Products/Development-hardware/nRF52840-Dongle", + "vendor": "Nordic Semiconductor" +} diff --git a/ports/nrf/boards/pca10090/board.json b/ports/nrf/boards/pca10090/board.json new file mode 100644 index 000000000..56525ef3a --- /dev/null +++ b/ports/nrf/boards/pca10090/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nRF59160-DK-prod-page.jpg" + ], + "mcu": "nrf91", + "product": "pca10090", + "thumbnail": "", + "url": "https://www.nordicsemi.com/Products/Development-hardware/nrf9160-dk", + "vendor": "Nordic Semiconductor" +} diff --git a/ports/nrf/boards/wt51822_s4at/board.json b/ports/nrf/boards/wt51822_s4at/board.json new file mode 100644 index 000000000..89d008c6f --- /dev/null +++ b/ports/nrf/boards/wt51822_s4at/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "https://4tronix.co.uk/picobot2/WT51822-S4AT.pdf", + "features": [], + "images": [ + "WT51822-S4AT.jpg" + ], + "mcu": "nrf51", + "product": "wt51822_s4at", + "thumbnail": "", + "url": "http://www.wireless-tag.com/portfolio/wt51822-s4at-2/", + "vendor": "Wireless-Tag" +} diff --git a/ports/nrf/main.c b/ports/nrf/main.c index 254d9491c..2ec16194c 100644 --- a/ports/nrf/main.c +++ b/ports/nrf/main.c @@ -106,28 +106,6 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { extern uint32_t _heap_start; extern uint32_t _heap_end; -#if MICROPY_HW_ENABLE_INTERNAL_FLASH_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; -} -#endif - int main(int argc, char **argv) { @@ -151,13 +129,8 @@ soft_reset: gc_init(&_heap_start, &_heap_end); mp_init(); - mp_obj_list_init(mp_sys_path, 0); - 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); - readline_init0(); - #if MICROPY_PY_MACHINE_HW_SPI spi_init0(); #endif @@ -203,11 +176,11 @@ soft_reset: // 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((mp_obj_t)&nrf_flash_obj, mount_point); + int ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point); if ((ret == -MP_ENODEV) || (ret == -MP_EIO)) { pyexec_frozen_module("_mkfs.py"); // Frozen script for formatting flash filesystem. - ret = vfs_mount_and_chdir((mp_obj_t)&nrf_flash_obj, mount_point); + ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point); } if (ret != 0) { diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 8a622d811..3ffb092c6 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -66,7 +66,6 @@ #endif #define MICROPY_OPT_COMPUTED_GOTO (0) -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) #define MICROPY_OPT_MPZ_BITWISE (0) // fatfs configuration used in ffconf.h @@ -136,6 +135,7 @@ #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PULSE (0) +#define MICROPY_PY_MACHINE_SOFTI2C (MICROPY_PY_MACHINE_I2C) #define MICROPY_PY_MACHINE_SPI (0) #define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0) #define MICROPY_PY_FRAMEBUF (0) diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index fd7ec65e0..0009ab2cd 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -25,11 +25,6 @@ if(NOT MICROPY_BOARD) set(MICROPY_BOARD PICO) endif() -# Set the PICO_BOARD if it's not already set. -if(NOT PICO_BOARD) - string(TOLOWER ${MICROPY_BOARD} PICO_BOARD) -endif() - # Set the board directory and check that it exists. if(NOT MICROPY_BOARD_DIR) set(MICROPY_BOARD_DIR ${MICROPY_PORT_DIR}/boards/${MICROPY_BOARD}) @@ -41,6 +36,11 @@ endif() # Include board config include(${MICROPY_BOARD_DIR}/mpconfigboard.cmake) +# Set the PICO_BOARD if it's not already set (allow a board to override it). +if(NOT PICO_BOARD) + string(TOLOWER ${MICROPY_BOARD} PICO_BOARD) +endif() + # Include component cmake fragments include(${MICROPY_DIR}/py/py.cmake) include(${MICROPY_DIR}/extmod/extmod.cmake) @@ -66,6 +66,7 @@ set(MICROPY_SOURCE_LIB ${MICROPY_DIR}/lib/littlefs/lfs2_util.c ${MICROPY_DIR}/lib/oofatfs/ff.c ${MICROPY_DIR}/lib/oofatfs/ffunicode.c + ${MICROPY_DIR}/shared/netutils/netutils.c ${MICROPY_DIR}/shared/readline/readline.c ${MICROPY_DIR}/shared/runtime/gchelper_m0.s ${MICROPY_DIR}/shared/runtime/gchelper_native.c @@ -78,14 +79,16 @@ set(MICROPY_SOURCE_LIB set(MICROPY_SOURCE_DRIVERS ${MICROPY_DIR}/drivers/bus/softspi.c + ${MICROPY_DIR}/drivers/dht/dht.c ) set(MICROPY_SOURCE_PORT fatfs_port.c machine_adc.c + machine_bitstream.c machine_i2c.c + machine_i2s.c machine_pin.c - machine_pwm.c machine_rtc.c machine_spi.c machine_timer.c @@ -112,8 +115,8 @@ set(MICROPY_SOURCE_QSTR ${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c ${PROJECT_SOURCE_DIR}/machine_adc.c ${PROJECT_SOURCE_DIR}/machine_i2c.c + ${PROJECT_SOURCE_DIR}/machine_i2s.c ${PROJECT_SOURCE_DIR}/machine_pin.c - ${PROJECT_SOURCE_DIR}/machine_pwm.c ${PROJECT_SOURCE_DIR}/machine_rtc.c ${PROJECT_SOURCE_DIR}/machine_spi.c ${PROJECT_SOURCE_DIR}/machine_timer.c @@ -161,6 +164,58 @@ set(PICO_SDK_COMPONENTS tinyusb_device ) +if(MICROPY_PY_BLUETOOTH) + list(APPEND MICROPY_SOURCE_PORT mpbthciport.c) + target_compile_definitions(${MICROPY_TARGET} PRIVATE + MICROPY_PY_BLUETOOTH=1 + MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1 + MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE=1 + MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1 + MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS=1 + ) +endif() + +if(MICROPY_BLUETOOTH_NIMBLE) + list(APPEND MICROPY_SOURCE_PORT mpnimbleport.c) + target_compile_definitions(${MICROPY_TARGET} PRIVATE + MICROPY_BLUETOOTH_NIMBLE=1 + MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY=0 + ) + target_compile_options(${MICROPY_TARGET} PRIVATE + # TODO: This flag is currently needed to make nimble build. + -Wno-unused-but-set-variable + ) + include(${MICROPY_DIR}/extmod/nimble/nimble.cmake) + target_link_libraries(${MICROPY_TARGET} micropy_extmod_nimble) + get_target_property(NIMBLE_INCLUDE micropy_extmod_nimble INTERFACE_INCLUDE_DIRECTORIES) + list(APPEND MICROPY_INC_CORE ${NIMBLE_INCLUDE}) +endif() + +if (MICROPY_PY_NETWORK_NINAW10) + target_compile_definitions(${MICROPY_TARGET} PRIVATE + MICROPY_PY_NETWORK_NINAW10=1 + ) + + target_include_directories(${MICROPY_TARGET} PRIVATE + ${MICROPY_DIR}/drivers/ninaw10/ + ) + + # Enable NINA-W10 WiFi and Bluetooth drivers. + list(APPEND MICROPY_SOURCE_DRIVERS + ${MICROPY_DIR}/drivers/ninaw10/nina_bt_hci.c + ${MICROPY_DIR}/drivers/ninaw10/nina_wifi_drv.c + ${MICROPY_DIR}/drivers/ninaw10/nina_wifi_bsp.c + ) + + list(APPEND MICROPY_SOURCE_EXTMOD + ${MICROPY_DIR}/extmod/network_ninaw10.c + ) + + list(APPEND MICROPY_SOURCE_QSTR + ${MICROPY_DIR}/extmod/network_ninaw10.c + ) +endif() + # Define mpy-cross flags and frozen manifest set(MICROPY_CROSS_FLAGS -march=armv7m) if (NOT MICROPY_FROZEN_MANIFEST) diff --git a/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json new file mode 100644 index 000000000..a7db46938 --- /dev/null +++ b/ports/rp2/boards/ADAFRUIT_FEATHER_RP2040/board.json @@ -0,0 +1,23 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "Breadboard Friendly", + "Feather", + "RGB LED", + "SPI Flash", + "STEMMA QT/QWIIC", + "USB-C" + ], + "images": [ + "4884-06.jpg" + ], + "mcu": "rp2040", + "product": "Feather RP2040", + "thumbnail": "", + "url": "https://www.adafruit.com/product/4884", + "vendor": "Adafruit" +} diff --git a/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json new file mode 100644 index 000000000..7ca0db069 --- /dev/null +++ b/ports/rp2/boards/ADAFRUIT_ITSYBITSY_RP2040/board.json @@ -0,0 +1,20 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly", + "Micro USB", + "RGB LED", + "SPI Flash" + ], + "images": [ + "4888-05.jpg" + ], + "mcu": "rp2040", + "product": "ItsyBitsy RP2040", + "thumbnail": "", + "url": "https://www.adafruit.com/product/4888", + "vendor": "Adafruit" +} diff --git a/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json new file mode 100644 index 000000000..d63166616 --- /dev/null +++ b/ports/rp2/boards/ADAFRUIT_QTPY_RP2040/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly", + "Castellated Pads", + "RGB LED", + "SPI Flash", + "STEMMA QT/QWIIC", + "USB-C" + ], + "images": [ + "4900-12.jpg" + ], + "mcu": "rp2040", + "product": "QT Py RP2040", + "thumbnail": "", + "url": "https://www.adafruit.com/product/4900", + "vendor": "Adafruit" +} diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json new file mode 100644 index 000000000..ca7ba089b --- /dev/null +++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/board.json @@ -0,0 +1,25 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly", + "Castellated Pads", + "WiFi Nina-W102", + "Bluetooth Nina-W102", + "IMU LSM6DSOXTR", + "Crypto IC ATECC608A-MAHDA-T", + "Microphone MP34DT05", + "SPI Flash 16MB", + "USB-MICRO" + ], + "images": [ + "ABX00052_01.iso_999x750.jpg" + ], + "mcu": "RP2040", + "product": "Arduino Nano RP2040 Connect", + "thumbnail": "", + "url": "https://store-usa.arduino.cc/products/arduino-nano-rp2040-connect", + "vendor": "Arduino" +} diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py new file mode 100644 index 000000000..a9c81576d --- /dev/null +++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/manifest.py @@ -0,0 +1,9 @@ +include("$(PORT_DIR)/boards/manifest.py") +freeze("$(MPY_DIR)/drivers/lsm6dsox/", "lsm6dsox.py") +include( + "$(MPY_LIB_DIR)/micropython/bluetooth/aioble/manifest.py", + client=True, + central=True, + l2cap=True, + security=True, +) diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.cmake b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.cmake new file mode 100644 index 000000000..b31109ac5 --- /dev/null +++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.cmake @@ -0,0 +1,6 @@ +# cmake file for Arduino Nano RP2040 Connect. +set(MICROPY_PY_BLUETOOTH 1) +set(MICROPY_BLUETOOTH_NIMBLE 1) +set(MICROPY_PY_NETWORK_NINAW10 1) +set(MICROPY_HW_ENABLE_DOUBLE_TAP 1) +set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) diff --git a/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h new file mode 100644 index 000000000..57c2d7879 --- /dev/null +++ b/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/mpconfigboard.h @@ -0,0 +1,47 @@ +//Board config for Arduino Nano RP2040 Connect. + +// Board and hardware specific configuration +#define MICROPY_HW_BOARD_NAME "Arduino Nano RP2040 Connect" +#define MICROPY_HW_FLASH_STORAGE_BYTES (8 * 1024 * 1024) + +// Enable networking and sockets. +#define MICROPY_PY_NETWORK (1) +#define MICROPY_PY_USOCKET (1) + +// Enable USB Mass Storage with FatFS filesystem. +#define MICROPY_HW_USB_MSC (1) +#define MICROPY_HW_USB_VID (0x2341) +#define MICROPY_HW_USB_PID (0x015e) + +// UART 1 config. +#define MICROPY_HW_UART1_TX (8) +#define MICROPY_HW_UART1_RX (9) +#define MICROPY_HW_UART1_CTS (10) +#define MICROPY_HW_UART1_RTS (11) + +// SPI 1 config. +#define MICROPY_HW_SPI1_SCK (14) +#define MICROPY_HW_SPI1_MOSI (11) +#define MICROPY_HW_SPI1_MISO (8) + +// I2C0 config. +#define MICROPY_HW_I2C0_SCL (13) +#define MICROPY_HW_I2C0_SDA (12) + +// I2C1 config. +#define MICROPY_HW_I2C1_SCL (27) +#define MICROPY_HW_I2C1_SDA (26) + +// Bluetooth config. +#define MICROPY_HW_BLE_UART_ID (1) +#define MICROPY_HW_BLE_UART_BAUDRATE (119600) + +// WiFi/NINA-W10 config. +#define MICROPY_HW_WIFI_SPI_ID (1) +#define MICROPY_HW_WIFI_SPI_BAUDRATE (8 * 1000 * 1000) + +// ublox Nina-W10 module config. +#define MICROPY_HW_NINA_RESET (3) +#define MICROPY_HW_NINA_GPIO0 (2) +#define MICROPY_HW_NINA_GPIO1 (9) +#define MICROPY_HW_NINA_ACK (10) diff --git a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json new file mode 100644 index 000000000..1b9e11314 --- /dev/null +++ b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "USB Stick form factor", + "Breadboard Friendly", + "Reset/User button", + "Red/green/orange/blue leds", + "1MB SPI Flash", + "USB-A" + ], + "images": [ + "pybstick-rp2040-26-broches-micropython-c.jpg" + ], + "mcu": "rp2040", + "product": "PYBSTICK26 RP2040", + "thumbnail": "", + "url": "https://shop.mchobby.be/product.php?id_product=2331", + "vendor": "McHobby" +} diff --git a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake new file mode 100644 index 000000000..9add51a78 --- /dev/null +++ b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.cmake @@ -0,0 +1,3 @@ +# cmake file + +set(PICO_BOARD pybstick26_rp2040) diff --git a/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.h b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.h new file mode 100644 index 000000000..4c7153569 --- /dev/null +++ b/ports/rp2/boards/GARATRONIC_PYBSTICK26_RP2040/mpconfigboard.h @@ -0,0 +1,3 @@ +// Board and hardware specific configuration +#define MICROPY_HW_BOARD_NAME "GARATRONIC_PYBSTICK26_RP2040" +#define MICROPY_HW_FLASH_STORAGE_BYTES (384 * 1024) diff --git a/ports/rp2/boards/PICO/board.json b/ports/rp2/boards/PICO/board.json new file mode 100644 index 000000000..b8ccb3ba5 --- /dev/null +++ b/ports/rp2/boards/PICO/board.json @@ -0,0 +1,20 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Breadboard friendly", + "Castellated Pads", + "Micro USB" + ], + "id": "rp2-pico", + "images": [ + "rp2-pico.jpg" + ], + "mcu": "rp2040", + "product": "Pico", + "thumbnail": "", + "url": "https://www.raspberrypi.org/products/raspberry-pi-pico/", + "vendor": "Raspberry Pi" +} diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json new file mode 100644 index 000000000..9121154d8 --- /dev/null +++ b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "Breadboard Friendly", + "Castellated Pads", + "SPI Flash", + "STEMMA QT/QWIIC", + "USB-C" + ], + "images": [ + "PimoroniPicoLipo_1of3_1024x1024.jpg" + ], + "mcu": "rp2040", + "product": "Pico LiPo (16MiB)", + "thumbnail": "", + "url": "https://shop.pimoroni.com/products/pimoroni-pico-lipo", + "vendor": "Pimoroni" +} diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h index 68478f761..134c2ff78 100644 --- a/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h +++ b/ports/rp2/boards/PIMORONI_PICOLIPO_16MB/mpconfigboard.h @@ -1,7 +1,7 @@ // https://shop.pimoroni.com/products/pimoroni-pico-lipo?variant=39335427080275 #define MICROPY_HW_BOARD_NAME "Pimoroni Pico LiPo 16MB" -#define MICROPY_HW_FLASH_STORAGE_BYTES (7 * 1024 * 1024) +#define MICROPY_HW_FLASH_STORAGE_BYTES (15 * 1024 * 1024) #define MICROPY_HW_USB_VID (0x2E8A) #define MICROPY_HW_USB_PID (0x1003) diff --git a/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json new file mode 100644 index 000000000..69d853239 --- /dev/null +++ b/ports/rp2/boards/PIMORONI_PICOLIPO_4MB/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "Breadboard Friendly", + "Castellated Pads", + "SPI Flash", + "STEMMA QT/QWIIC", + "USB-C" + ], + "images": [ + "PimoroniPicoLipo_1of3_1024x1024.jpg" + ], + "mcu": "rp2040", + "product": "Pico LiPo (4MiB)", + "thumbnail": "", + "url": "https://shop.pimoroni.com/products/pimoroni-pico-lipo", + "vendor": "Pimoroni" +} diff --git a/ports/rp2/boards/PIMORONI_TINY2040/board.json b/ports/rp2/boards/PIMORONI_TINY2040/board.json new file mode 100644 index 000000000..753a25bea --- /dev/null +++ b/ports/rp2/boards/PIMORONI_TINY2040/board.json @@ -0,0 +1,20 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly", + "Castellated Pads", + "RGB LED", + "USB-C" + ], + "images": [ + "tiny-2040-on-white-1_1024x1024.jpg" + ], + "mcu": "rp2040", + "product": "Tiny2040", + "thumbnail": "", + "url": "https://shop.pimoroni.com/products/tiny-2040", + "vendor": "Pimoroni" +} diff --git a/ports/rp2/boards/SPARKFUN_PROMICRO/board.json b/ports/rp2/boards/SPARKFUN_PROMICRO/board.json new file mode 100644 index 000000000..a0d39165a --- /dev/null +++ b/ports/rp2/boards/SPARKFUN_PROMICRO/board.json @@ -0,0 +1,21 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly", + "Castellated Pads", + "RGB LED", + "STEMMA QT/QWIIC", + "USB-C" + ], + "images": [ + "17745-SparkFun_Thing_Plus_-_RP2040-01a.jpg" + ], + "mcu": "rp2040", + "product": "Pro Micro RP2040", + "thumbnail": "", + "url": "https://www.sparkfun.com/products/18288", + "vendor": "Sparkfun" +} diff --git a/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json b/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json new file mode 100644 index 000000000..871a411b5 --- /dev/null +++ b/ports/rp2/boards/SPARKFUN_THINGPLUS/board.json @@ -0,0 +1,24 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "Breadboard Friendly", + "Feather", + "MicroSD", + "RGB LED", + "SPI Flash", + "STEMMA QT/QWIIC", + "USB-C" + ], + "images": [ + "17745-SparkFun_Thing_Plus_-_RP2040-01a.jpg" + ], + "mcu": "rp2040", + "product": "Thing Plus RP2040", + "thumbnail": "", + "url": "https://www.sparkfun.com/products/17745", + "vendor": "Sparkfun" +} diff --git a/ports/rp2/boards/deploy.md b/ports/rp2/boards/deploy.md new file mode 100644 index 000000000..4e76dfa29 --- /dev/null +++ b/ports/rp2/boards/deploy.md @@ -0,0 +1,8 @@ +### Flashing via UF2 bootloader + +To get the board in bootloader mode ready for the firmware update, execute +`machine.bootloader()` at the MicroPython REPL. Alternatively, hold +down the BOOTSEL button while plugging the board into USB. The uf2 file below +should then be copied to the USB mass storage device that appears. Once +programming of the new firmware is complete the device will automatically reset +and be ready for use. diff --git a/ports/rp2/boards/manifest.py b/ports/rp2/boards/manifest.py index 9df589f12..b0e5e3155 100644 --- a/ports/rp2/boards/manifest.py +++ b/ports/rp2/boards/manifest.py @@ -1,3 +1,5 @@ freeze("$(PORT_DIR)/modules") freeze("$(MPY_DIR)/drivers/onewire") +freeze("$(MPY_DIR)/drivers/dht", "dht.py") include("$(MPY_DIR)/extmod/uasyncio/manifest.py") +include("$(MPY_DIR)/drivers/neopixel/manifest.py") diff --git a/ports/rp2/machine_bitstream.c b/ports/rp2/machine_bitstream.c new file mode 100644 index 000000000..b65ec0214 --- /dev/null +++ b/ports/rp2/machine_bitstream.c @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 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. + */ + +// This is a translation of the cycle counter implementation in ports/stm32/machine_bitstream.c. + +#include "py/mpconfig.h" +#include "py/mphal.h" +#include "hardware/structs/systick.h" + +#if MICROPY_PY_MACHINE_BITSTREAM + +#define MP_HAL_BITSTREAM_NS_OVERHEAD (9) + +void __time_critical_func(machine_bitstream_high_low)(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len) { + uint32_t fcpu_mhz = mp_hal_get_cpu_freq() / 1000000; + // Convert ns to clock ticks [high_time_0, period_0, high_time_1, period_1]. + for (size_t i = 0; i < 4; ++i) { + timing_ns[i] = fcpu_mhz * timing_ns[i] / 1000; + if (timing_ns[i] > (2 * MP_HAL_BITSTREAM_NS_OVERHEAD)) { + timing_ns[i] -= MP_HAL_BITSTREAM_NS_OVERHEAD; + } + if (i % 2 == 1) { + // Convert low_time to period (i.e. add high_time). + timing_ns[i] += timing_ns[i - 1] - MP_HAL_BITSTREAM_NS_OVERHEAD; + } + } + mp_hal_pin_output(pin); + // Enable the systick counter, source CPU clock. + systick_hw->csr = 5; + + uint32_t irq_state = mp_hal_quiet_timing_enter(); + + for (size_t i = 0; i < len; ++i) { + uint8_t b = buf[i]; + for (size_t j = 0; j < 8; ++j) { + uint32_t *t = &timing_ns[b >> 6 & 2]; + uint32_t start_ticks = systick_hw->cvr = SYSTICK_MAX; + mp_hal_pin_high(pin); + while ((start_ticks - systick_hw->cvr) < t[0]) { + } + b <<= 1; + mp_hal_pin_low(pin); + while ((start_ticks - systick_hw->cvr) < t[1]) { + } + } + } + + mp_hal_quiet_timing_exit(irq_state); +} + +#endif // MICROPY_PY_MACHINE_BITSTREAM diff --git a/ports/rp2/machine_i2s.c b/ports/rp2/machine_i2s.c new file mode 100644 index 000000000..ec64f72ec --- /dev/null +++ b/ports/rp2/machine_i2s.c @@ -0,0 +1,1150 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Mike Teachman + * + * 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/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/misc.h" +#include "py/stream.h" +#include "py/objstr.h" +#include "modmachine.h" + +#include "hardware/pio.h" +#include "hardware/clocks.h" +#include "hardware/gpio.h" +#include "hardware/dma.h" +#include "hardware/irq.h" + +// The I2S class has 3 modes of operation: +// +// Mode1: Blocking +// - readinto() and write() methods block until the supplied buffer is filled (read) or emptied (write) +// - this is the default mode of operation +// +// Mode2: Non-Blocking +// - readinto() and write() methods return immediately +// - buffer filling and emptying happens asynchronously to the main MicroPython task +// - a callback function is called when the supplied buffer has been filled (read) or emptied (write) +// - non-blocking mode is enabled when a callback is set with the irq() method +// - the DMA IRQ handler is used to implement the asynchronous background operations +// +// Mode3: Uasyncio +// - implements the stream protocol +// - uasyncio mode is enabled when the ioctl() function is called +// - the state of the internal ring buffer is used to detect that I2S samples can be read or written +// +// The samples contained in the app buffer supplied for the readinto() and write() methods have the following convention: +// Mono: little endian format +// Stereo: little endian format, left channel first +// +// I2S terms: +// "frame": consists of two audio samples (Left audio sample + Right audio sample) +// +// Misc: +// - for Mono configuration: +// - readinto method: samples are gathered from the L channel only +// - write method: every sample is output to both the L and R channels +// - for readinto method the I2S hardware is read using 8-byte frames +// (this is standard for almost all I2S hardware, such as MEMS microphones) +// - the PIO is used to drive the I2S bus signals +// - all sample data transfers use non-blocking DMA +// - the DMA controller is configured with 2 DMA channels in chained mode + +#define MAX_I2S_RP2 (2) + +// The DMA buffer size was empirically determined. It is a tradeoff between: +// 1. memory use (smaller buffer size desirable to reduce memory footprint) +// 2. interrupt frequency (larger buffer size desirable to reduce interrupt frequency) +#define SIZEOF_DMA_BUFFER_IN_BYTES (256) +#define SIZEOF_HALF_DMA_BUFFER_IN_BYTES (SIZEOF_DMA_BUFFER_IN_BYTES / 2) +#define I2S_NUM_DMA_CHANNELS (2) + +// For non-blocking mode, to avoid underflow/overflow, sample data is written/read to/from the ring buffer at a rate faster +// than the DMA transfer rate +#define NON_BLOCKING_RATE_MULTIPLIER (4) +#define SIZEOF_NON_BLOCKING_COPY_IN_BYTES (SIZEOF_HALF_DMA_BUFFER_IN_BYTES * NON_BLOCKING_RATE_MULTIPLIER) + +#define NUM_I2S_USER_FORMATS (4) +#define I2S_RX_FRAME_SIZE_IN_BYTES (8) + +#define SAMPLES_PER_FRAME (2) +#define PIO_INSTRUCTIONS_PER_BIT (2) + +typedef enum { + RX, + TX +} i2s_mode_t; + +typedef enum { + MONO, + STEREO +} format_t; + +typedef enum { + BLOCKING, + NON_BLOCKING, + UASYNCIO +} io_mode_t; + +typedef enum { + GP_INPUT = 0, + GP_OUTPUT = 1 +} gpio_dir_t; + +typedef struct _ring_buf_t { + uint8_t *buffer; + size_t head; + size_t tail; + size_t size; +} ring_buf_t; + +typedef struct _non_blocking_descriptor_t { + mp_buffer_info_t appbuf; + uint32_t index; + bool copy_in_progress; +} non_blocking_descriptor_t; + +typedef struct _machine_i2s_obj_t { + mp_obj_base_t base; + uint8_t i2s_id; + mp_hal_pin_obj_t sck; + mp_hal_pin_obj_t ws; + mp_hal_pin_obj_t sd; + i2s_mode_t mode; + int8_t bits; + format_t format; + int32_t rate; + int32_t ibuf; + mp_obj_t callback_for_non_blocking; + io_mode_t io_mode; + PIO pio; + uint8_t sm; + const pio_program_t *pio_program; + uint prog_offset; + int dma_channel[I2S_NUM_DMA_CHANNELS]; + uint8_t dma_buffer[SIZEOF_DMA_BUFFER_IN_BYTES]; + ring_buf_t ring_buffer; + uint8_t *ring_buffer_storage; + non_blocking_descriptor_t non_blocking_descriptor; +} machine_i2s_obj_t; + +// The frame map is used with the readinto() method to transform the audio sample data coming +// from DMA memory (32-bit stereo) to the format specified +// in the I2S constructor. e.g. 16-bit mono +STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYTES] = { + {-1, -1, 0, 1, -1, -1, -1, -1 }, // Mono, 16-bits + { 0, 1, 2, 3, -1, -1, -1, -1 }, // Mono, 32-bits + {-1, -1, 0, 1, -1, -1, 2, 3 }, // Stereo, 16-bits + { 0, 1, 2, 3, 4, 5, 6, 7 }, // Stereo, 32-bits +}; + +STATIC const PIO pio_instances[NUM_PIOS] = {pio0, pio1}; + +// PIO program for 16-bit write +// set(x, 14) .side(0b01) +// label('left_channel') +// out(pins, 1) .side(0b00) +// jmp(x_dec, "left_channel") .side(0b01) +// out(pins, 1) .side(0b10) +// set(x, 14) .side(0b11) +// label('right_channel') +// out(pins, 1) .side(0b10) +// jmp(x_dec, "right_channel") .side(0b11) +// out(pins, 1) .side(0b00) +STATIC const uint16_t pio_instructions_write_16[] = {59438, 24577, 2113, 28673, 63534, 28673, 6213, 24577}; +STATIC const pio_program_t pio_write_16 = { + pio_instructions_write_16, + sizeof(pio_instructions_write_16) / sizeof(uint16_t), + -1 +}; + +// PIO program for 32-bit write +// set(x, 30) .side(0b01) +// label('left_channel') +// out(pins, 1) .side(0b00) +// jmp(x_dec, "left_channel") .side(0b01) +// out(pins, 1) .side(0b10) +// set(x, 30) .side(0b11) +// label('right_channel') +// out(pins, 1) .side(0b10) +// jmp(x_dec, "right_channel") .side(0b11) +// out(pins, 1) .side(0b00) +STATIC const uint16_t pio_instructions_write_32[] = {59454, 24577, 2113, 28673, 63550, 28673, 6213, 24577}; +STATIC const pio_program_t pio_write_32 = { + pio_instructions_write_32, + sizeof(pio_instructions_write_32) / sizeof(uint16_t), + -1 +}; + +// PIO program for 32-bit read +// set(x, 30) .side(0b00) +// label('left_channel') +// in_(pins, 1) .side(0b01) +// jmp(x_dec, "left_channel") .side(0b00) +// in_(pins, 1) .side(0b11) +// set(x, 30) .side(0b10) +// label('right_channel') +// in_(pins, 1) .side(0b11) +// jmp(x_dec, "right_channel") .side(0b10) +// in_(pins, 1) .side(0b01) +STATIC const uint16_t pio_instructions_read_32[] = {57406, 18433, 65, 22529, 61502, 22529, 4165, 18433}; +STATIC const pio_program_t pio_read_32 = { + pio_instructions_read_32, + sizeof(pio_instructions_read_32) / sizeof(uint16_t), + -1 +}; + +STATIC uint8_t dma_get_bits(i2s_mode_t mode, int8_t bits); +STATIC void dma_irq0_handler(void); +STATIC void dma_irq1_handler(void); +STATIC mp_obj_t machine_i2s_deinit(mp_obj_t self_in); + +void machine_i2s_init0(void) { + for (uint8_t i = 0; i < MAX_I2S_RP2; i++) { + MP_STATE_PORT(machine_i2s_obj[i]) = NULL; + } +} + +// Ring Buffer +// Thread safe when used with these constraints: +// - Single Producer, Single Consumer +// - Sequential atomic operations +// One byte of capacity is used to detect buffer empty/full + +STATIC void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size) { + rbuf->buffer = buffer; + rbuf->size = size; + rbuf->head = 0; + rbuf->tail = 0; +} + +STATIC bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) { + size_t next_tail = (rbuf->tail + 1) % rbuf->size; + + if (next_tail != rbuf->head) { + rbuf->buffer[rbuf->tail] = data; + rbuf->tail = next_tail; + return true; + } + + // full + return false; +} + +STATIC bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) { + if (rbuf->head == rbuf->tail) { + // empty + return false; + } + + *data = rbuf->buffer[rbuf->head]; + rbuf->head = (rbuf->head + 1) % rbuf->size; + return true; +} + +STATIC bool ringbuf_is_empty(ring_buf_t *rbuf) { + return rbuf->head == rbuf->tail; +} + +STATIC bool ringbuf_is_full(ring_buf_t *rbuf) { + return ((rbuf->tail + 1) % rbuf->size) == rbuf->head; +} + +STATIC size_t ringbuf_available_data(ring_buf_t *rbuf) { + return (rbuf->tail - rbuf->head + rbuf->size) % rbuf->size; +} + +STATIC size_t ringbuf_available_space(ring_buf_t *rbuf) { + return rbuf->size - ringbuf_available_data(rbuf) - 1; +} + +STATIC int8_t get_frame_mapping_index(int8_t bits, format_t format) { + if (format == MONO) { + if (bits == 16) { + return 0; + } else { // 32 bits + return 1; + } + } else { // STEREO + if (bits == 16) { + return 2; + } else { // 32 bits + return 3; + } + } +} + +STATIC uint32_t fill_appbuf_from_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) { + + // copy audio samples from the ring buffer to the app buffer + // loop, copying samples until the app buffer is filled + // For uasyncio mode, the loop will make an early exit if the ring buffer becomes empty + // Example: + // a MicroPython I2S object is configured for 16-bit mono (2 bytes per audio sample). + // For every frame coming from the ring buffer (8 bytes), 2 bytes are "cherry picked" and + // copied to the supplied app buffer. + // Thus, for every 1 byte copied to the app buffer, 4 bytes are read from the ring buffer. + // If a 8kB app buffer is supplied, 32kB of audio samples is read from the ring buffer. + + uint32_t num_bytes_copied_to_appbuf = 0; + uint8_t *app_p = (uint8_t *)appbuf->buf; + uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); + uint32_t num_bytes_needed_from_ringbuf = appbuf->len * (I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); + uint8_t discard_byte; + while (num_bytes_needed_from_ringbuf) { + + uint8_t f_index = get_frame_mapping_index(self->bits, self->format); + + for (uint8_t i = 0; i < I2S_RX_FRAME_SIZE_IN_BYTES; i++) { + int8_t r_to_a_mapping = i2s_frame_map[f_index][i]; + if (r_to_a_mapping != -1) { + if (self->io_mode == BLOCKING) { + // poll the ringbuf until a sample becomes available, copy into appbuf using the mapping transform + while (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) { + ; + } + num_bytes_copied_to_appbuf++; + } else if (self->io_mode == UASYNCIO) { + if (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) { + // ring buffer is empty, exit + goto exit; + } else { + num_bytes_copied_to_appbuf++; + } + } else { + return 0; // should never get here (non-blocking mode does not use this function) + } + } else { // r_a_mapping == -1 + // discard unused byte from ring buffer + if (self->io_mode == BLOCKING) { + // poll the ringbuf until a sample becomes available + while (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) { + ; + } + } else if (self->io_mode == UASYNCIO) { + if (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) { + // ring buffer is empty, exit + goto exit; + } + } else { + return 0; // should never get here (non-blocking mode does not use this function) + } + } + num_bytes_needed_from_ringbuf--; + } + app_p += appbuf_sample_size_in_bytes; + } +exit: + return num_bytes_copied_to_appbuf; +} + +// function is used in IRQ context +STATIC void fill_appbuf_from_ringbuf_non_blocking(machine_i2s_obj_t *self) { + + // attempt to copy a block of audio samples from the ring buffer to the supplied app buffer. + // audio samples will be formatted as part of the copy operation + + uint32_t num_bytes_copied_to_appbuf = 0; + uint8_t *app_p = &(((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index]); + + uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); + uint32_t num_bytes_remaining_to_copy_to_appbuf = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index; + uint32_t num_bytes_remaining_to_copy_from_ring_buffer = num_bytes_remaining_to_copy_to_appbuf * + (I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); + uint32_t num_bytes_needed_from_ringbuf = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy_from_ring_buffer); + uint8_t discard_byte; + if (ringbuf_available_data(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) { + while (num_bytes_needed_from_ringbuf) { + + uint8_t f_index = get_frame_mapping_index(self->bits, self->format); + + for (uint8_t i = 0; i < I2S_RX_FRAME_SIZE_IN_BYTES; i++) { + int8_t r_to_a_mapping = i2s_frame_map[f_index][i]; + if (r_to_a_mapping != -1) { + ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping); + num_bytes_copied_to_appbuf++; + } else { // r_a_mapping == -1 + // discard unused byte from ring buffer + ringbuf_pop(&self->ring_buffer, &discard_byte); + } + num_bytes_needed_from_ringbuf--; + } + app_p += appbuf_sample_size_in_bytes; + } + self->non_blocking_descriptor.index += num_bytes_copied_to_appbuf; + + if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) { + self->non_blocking_descriptor.copy_in_progress = false; + mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self)); + } + } +} + +STATIC uint32_t copy_appbuf_to_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) { + + // copy audio samples from the app buffer to the ring buffer + // loop, reading samples until the app buffer is emptied + // for uasyncio mode, the loop will make an early exit if the ring buffer becomes full + + uint32_t a_index = 0; + + while (a_index < appbuf->len) { + if (self->io_mode == BLOCKING) { + // copy a byte to the ringbuf when space becomes available + while (ringbuf_push(&self->ring_buffer, ((uint8_t *)appbuf->buf)[a_index]) == false) { + ; + } + a_index++; + } else if (self->io_mode == UASYNCIO) { + if (ringbuf_push(&self->ring_buffer, ((uint8_t *)appbuf->buf)[a_index]) == false) { + // ring buffer is full, exit + break; + } else { + a_index++; + } + } else { + return 0; // should never get here (non-blocking mode does not use this function) + } + } + + return a_index; +} + +// function is used in IRQ context +STATIC void copy_appbuf_to_ringbuf_non_blocking(machine_i2s_obj_t *self) { + + // copy audio samples from app buffer into ring buffer + uint32_t num_bytes_remaining_to_copy = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index; + uint32_t num_bytes_to_copy = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy); + + if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_to_copy) { + for (uint32_t i = 0; i < num_bytes_to_copy; i++) { + ringbuf_push(&self->ring_buffer, + ((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index + i]); + } + + self->non_blocking_descriptor.index += num_bytes_to_copy; + if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) { + self->non_blocking_descriptor.copy_in_progress = false; + mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self)); + } + } +} + +// function is used in IRQ context +STATIC void empty_dma(machine_i2s_obj_t *self, uint8_t *dma_buffer_p) { + // when space exists, copy samples into ring buffer + if (ringbuf_available_space(&self->ring_buffer) >= SIZEOF_HALF_DMA_BUFFER_IN_BYTES) { + for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES; i++) { + ringbuf_push(&self->ring_buffer, dma_buffer_p[i]); + } + } +} + +// function is used in IRQ context +STATIC void feed_dma(machine_i2s_obj_t *self, uint8_t *dma_buffer_p) { + // when data exists, copy samples from ring buffer + if (ringbuf_available_data(&self->ring_buffer) >= SIZEOF_HALF_DMA_BUFFER_IN_BYTES) { + + // copy a block of samples from the ring buffer to the dma buffer. + // STM32 HAL API has a stereo I2S implementation, but not mono + // mono format is implemented by duplicating each sample into both L and R channels. + if ((self->format == MONO) && (self->bits == 16)) { + for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES / 4; i++) { + for (uint8_t b = 0; b < sizeof(uint16_t); b++) { + ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i * 4 + b]); + dma_buffer_p[i * 4 + b + 2] = dma_buffer_p[i * 4 + b]; // duplicated mono sample + } + } + } else if ((self->format == MONO) && (self->bits == 32)) { + for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES / 8; i++) { + for (uint8_t b = 0; b < sizeof(uint32_t); b++) { + ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i * 8 + b]); + dma_buffer_p[i * 8 + b + 4] = dma_buffer_p[i * 8 + b]; // duplicated mono sample + } + } + } else { // STEREO, both 16-bit and 32-bit + for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES; i++) { + ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i]); + } + } + } else { + // underflow. clear buffer to transmit "silence" on the I2S bus + memset(dma_buffer_p, 0, SIZEOF_HALF_DMA_BUFFER_IN_BYTES); + } +} + +STATIC void irq_configure(machine_i2s_obj_t *self) { + if (self->i2s_id == 0) { + irq_set_exclusive_handler(DMA_IRQ_0, dma_irq0_handler); + irq_set_enabled(DMA_IRQ_0, true); + } else { + irq_set_exclusive_handler(DMA_IRQ_1, dma_irq1_handler); + irq_set_enabled(DMA_IRQ_1, true); + } +} + +STATIC void irq_deinit(machine_i2s_obj_t *self) { + if (self->i2s_id == 0) { + irq_set_enabled(DMA_IRQ_0, false); + irq_remove_handler(DMA_IRQ_0, dma_irq0_handler); + } else { + irq_set_enabled(DMA_IRQ_1, false); + irq_remove_handler(DMA_IRQ_1, dma_irq1_handler); + } +} + +STATIC void pio_configure(machine_i2s_obj_t *self) { + if (self->mode == TX) { + if (self->bits == 16) { + self->pio_program = &pio_write_16; + } else { + self->pio_program = &pio_write_32; + } + } else { // RX + self->pio_program = &pio_read_32; + } + + // find a PIO with a free state machine and adequate program space + PIO candidate_pio; + bool is_free_sm; + bool can_add_program; + for (uint8_t p = 0; p < NUM_PIOS; p++) { + candidate_pio = pio_instances[p]; + is_free_sm = false; + can_add_program = false; + + for (uint8_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { + if (!pio_sm_is_claimed(candidate_pio, sm)) { + is_free_sm = true; + break; + } + } + + if (pio_can_add_program(candidate_pio, self->pio_program)) { + can_add_program = true; + } + + if (is_free_sm && can_add_program) { + break; + } + } + + if (!is_free_sm) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("no free state machines")); + } + + if (!can_add_program) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("not enough PIO program space")); + } + + self->pio = candidate_pio; + self->sm = pio_claim_unused_sm(self->pio, false); + self->prog_offset = pio_add_program(self->pio, self->pio_program); + pio_sm_init(self->pio, self->sm, self->prog_offset, NULL); + + pio_sm_config config = pio_get_default_sm_config(); + + float pio_freq = self->rate * + SAMPLES_PER_FRAME * + dma_get_bits(self->mode, self->bits) * + PIO_INSTRUCTIONS_PER_BIT; + float clkdiv = clock_get_hz(clk_sys) / pio_freq; + sm_config_set_clkdiv(&config, clkdiv); + + if (self->mode == TX) { + sm_config_set_out_pins(&config, self->sd, 1); + sm_config_set_out_shift(&config, false, true, dma_get_bits(self->mode, self->bits)); + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX); // double TX FIFO size + } else { // RX + sm_config_set_in_pins(&config, self->sd); + sm_config_set_in_shift(&config, false, true, dma_get_bits(self->mode, self->bits)); + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX); // double RX FIFO size + } + + sm_config_set_sideset(&config, 2, false, false); + sm_config_set_sideset_pins(&config, self->sck); + sm_config_set_wrap(&config, self->prog_offset, self->prog_offset + self->pio_program->length - 1); + pio_sm_set_config(self->pio, self->sm, &config); +} + +STATIC void pio_deinit(machine_i2s_obj_t *self) { + if (self->pio) { + pio_sm_set_enabled(self->pio, self->sm, false); + pio_sm_unclaim(self->pio, self->sm); + pio_remove_program(self->pio, self->pio_program, self->prog_offset); + } +} + +STATIC void gpio_init_i2s(PIO pio, uint8_t sm, mp_hal_pin_obj_t pin_num, uint8_t pin_val, gpio_dir_t pin_dir) { + uint32_t pinmask = 1 << pin_num; + pio_sm_set_pins_with_mask(pio, sm, pin_val << pin_num, pinmask); + pio_sm_set_pindirs_with_mask(pio, sm, pin_dir << pin_num, pinmask); + pio_gpio_init(pio, pin_num); +} + +STATIC void gpio_configure(machine_i2s_obj_t *self) { + gpio_init_i2s(self->pio, self->sm, self->sck, 0, GP_OUTPUT); + gpio_init_i2s(self->pio, self->sm, self->ws, 0, GP_OUTPUT); + if (self->mode == TX) { + gpio_init_i2s(self->pio, self->sm, self->sd, 0, GP_OUTPUT); + } else { // RX + gpio_init_i2s(self->pio, self->sm, self->sd, 0, GP_INPUT); + } +} + +STATIC uint8_t dma_get_bits(i2s_mode_t mode, int8_t bits) { + if (mode == TX) { + return bits; + } else { // RX + // always read 32 bit words for I2S e.g. I2S MEMS microphones + return 32; + } +} + +// determine which DMA channel is associated to this IRQ +STATIC uint dma_map_irq_to_channel(uint irq_index) { + for (uint ch = 0; ch < NUM_DMA_CHANNELS; ch++) { + if ((dma_irqn_get_channel_status(irq_index, ch))) { + return ch; + } + } + // This should never happen + return -1; +} + +// note: first DMA channel is mapped to the top half of buffer, second is mapped to the bottom half +STATIC uint8_t *dma_get_buffer(machine_i2s_obj_t *i2s_obj, uint channel) { + for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) { + if (i2s_obj->dma_channel[ch] == channel) { + return i2s_obj->dma_buffer + (SIZEOF_HALF_DMA_BUFFER_IN_BYTES * ch); + } + } + // This should never happen + return NULL; +} + +STATIC void dma_configure(machine_i2s_obj_t *self) { + uint8_t num_free_dma_channels = 0; + for (uint8_t ch = 0; ch < NUM_DMA_CHANNELS; ch++) { + if (!dma_channel_is_claimed(ch)) { + num_free_dma_channels++; + } + } + if (num_free_dma_channels < I2S_NUM_DMA_CHANNELS) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("cannot claim 2 DMA channels")); + } + + for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) { + self->dma_channel[ch] = dma_claim_unused_channel(false); + } + + // The DMA channels are chained together. The first DMA channel is used to access + // the top half of the DMA buffer. The second DMA channel accesses the bottom half of the DMA buffer. + // With chaining, when one DMA channel has completed a data transfer, the other + // DMA channel automatically starts a new data transfer. + enum dma_channel_transfer_size dma_size = (dma_get_bits(self->mode, self->bits) == 16) ? DMA_SIZE_16 : DMA_SIZE_32; + for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) { + dma_channel_config dma_config = dma_channel_get_default_config(self->dma_channel[ch]); + channel_config_set_transfer_data_size(&dma_config, dma_size); + channel_config_set_chain_to(&dma_config, self->dma_channel[(ch + 1) % I2S_NUM_DMA_CHANNELS]); + + uint8_t *dma_buffer = self->dma_buffer + (SIZEOF_HALF_DMA_BUFFER_IN_BYTES * ch); + if (self->mode == TX) { + channel_config_set_dreq(&dma_config, pio_get_dreq(self->pio, self->sm, true)); + channel_config_set_read_increment(&dma_config, true); + channel_config_set_write_increment(&dma_config, false); + dma_channel_configure(self->dma_channel[ch], + &dma_config, + (void *)&self->pio->txf[self->sm], // dest = PIO TX FIFO + dma_buffer, // src = DMA buffer + SIZEOF_HALF_DMA_BUFFER_IN_BYTES / (dma_get_bits(self->mode, self->bits) / 8), + false); + } else { // RX + channel_config_set_dreq(&dma_config, pio_get_dreq(self->pio, self->sm, false)); + channel_config_set_read_increment(&dma_config, false); + channel_config_set_write_increment(&dma_config, true); + dma_channel_configure(self->dma_channel[ch], + &dma_config, + dma_buffer, // dest = DMA buffer + (void *)&self->pio->rxf[self->sm], // src = PIO RX FIFO + SIZEOF_HALF_DMA_BUFFER_IN_BYTES / (dma_get_bits(self->mode, self->bits) / 8), + false); + } + } + + for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) { + dma_irqn_acknowledge_channel(self->i2s_id, self->dma_channel[ch]); // clear pending. e.g. from SPI + dma_irqn_set_channel_enabled(self->i2s_id, self->dma_channel[ch], true); + } +} + +STATIC void dma_deinit(machine_i2s_obj_t *self) { + for (uint8_t ch = 0; ch < I2S_NUM_DMA_CHANNELS; ch++) { + int channel = self->dma_channel[ch]; + + // unchain the channel to prevent triggering a transfer in the chained-to channel + dma_channel_config dma_config = dma_get_channel_config(channel); + channel_config_set_chain_to(&dma_config, channel); + dma_channel_set_config(channel, &dma_config, false); + + dma_irqn_set_channel_enabled(self->i2s_id, channel, false); + dma_channel_abort(channel); // in case a transfer is in flight + dma_channel_unclaim(channel); + } +} + +STATIC void dma_irq_handler(uint8_t irq_index) { + int dma_channel = dma_map_irq_to_channel(irq_index); + if (dma_channel == -1) { + // This should never happen + return; + } + + machine_i2s_obj_t *self = MP_STATE_PORT(machine_i2s_obj[irq_index]); + if (self == NULL) { + // This should never happen + return; + } + + uint8_t *dma_buffer = dma_get_buffer(self, dma_channel); + if (dma_buffer == NULL) { + // This should never happen + return; + } + + if (self->mode == TX) { + // for non-blocking operation handle the write() method requests. + if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) { + copy_appbuf_to_ringbuf_non_blocking(self); + } + + feed_dma(self, dma_buffer); + dma_irqn_acknowledge_channel(irq_index, dma_channel); + dma_channel_set_read_addr(dma_channel, dma_buffer, false); + } else { // RX + empty_dma(self, dma_buffer); + dma_irqn_acknowledge_channel(irq_index, dma_channel); + dma_channel_set_write_addr(dma_channel, dma_buffer, false); + + // for non-blocking operation handle the readinto() method requests. + if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) { + fill_appbuf_from_ringbuf_non_blocking(self); + } + } +} + +STATIC void dma_irq0_handler(void) { + dma_irq_handler(0); +} + +STATIC void dma_irq1_handler(void) { + dma_irq_handler(1); +} + +STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + enum { + ARG_sck, + ARG_ws, + ARG_sd, + ARG_mode, + ARG_bits, + ARG_format, + ARG_rate, + ARG_ibuf, + }; + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_ws, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_sd, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_rate, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_ibuf, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_pos_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // + // ---- Check validity of arguments ---- + // + + // are Pins valid? + mp_hal_pin_obj_t sck = args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_sck].u_obj); + mp_hal_pin_obj_t ws = args[ARG_ws].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_ws].u_obj); + mp_hal_pin_obj_t sd = args[ARG_sd].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_sd].u_obj); + + // does WS pin follow SCK pin? + // note: SCK and WS are implemented as PIO sideset pins. Sideset pins must be sequential. + if (ws != (sck + 1)) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid ws (must be sck+1)")); + } + + // is Mode valid? + i2s_mode_t i2s_mode = args[ARG_mode].u_int; + if ((i2s_mode != RX) && + (i2s_mode != TX)) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid mode")); + } + + // is Bits valid? + int8_t i2s_bits = args[ARG_bits].u_int; + if ((i2s_bits != 16) && + (i2s_bits != 32)) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid bits")); + } + + // is Format valid? + format_t i2s_format = args[ARG_format].u_int; + if ((i2s_format != MONO) && + (i2s_format != STEREO)) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid format")); + } + + // is Rate valid? + // Not checked + + // is Ibuf valid? + int32_t ring_buffer_len = args[ARG_ibuf].u_int; + if (ring_buffer_len > 0) { + self->ring_buffer_storage = m_new(uint8_t, ring_buffer_len); + ; + ringbuf_init(&self->ring_buffer, self->ring_buffer_storage, ring_buffer_len); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("invalid ibuf")); + } + + self->sck = sck; + self->ws = ws; + self->sd = sd; + self->mode = i2s_mode; + self->bits = i2s_bits; + self->format = i2s_format; + self->rate = args[ARG_rate].u_int; + self->ibuf = ring_buffer_len; + self->callback_for_non_blocking = MP_OBJ_NULL; + self->non_blocking_descriptor.copy_in_progress = false; + self->io_mode = BLOCKING; + + irq_configure(self); + pio_configure(self); + gpio_configure(self); + dma_configure(self); + + pio_sm_set_enabled(self->pio, self->sm, true); + dma_channel_start(self->dma_channel[0]); +} + +STATIC void machine_i2s_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "I2S(id=%u,\n" + "sck="MP_HAL_PIN_FMT ",\n" + "ws="MP_HAL_PIN_FMT ",\n" + "sd="MP_HAL_PIN_FMT ",\n" + "mode=%u,\n" + "bits=%u, format=%u,\n" + "rate=%d, ibuf=%d)", + self->i2s_id, + mp_hal_pin_name(self->sck), + mp_hal_pin_name(self->ws), + mp_hal_pin_name(self->sd), + self->mode, + self->bits, self->format, + self->rate, self->ibuf + ); +} + +STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) { + mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true); + uint8_t i2s_id = mp_obj_get_int(args[0]); + + if (i2s_id >= MAX_I2S_RP2) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid id")); + } + + machine_i2s_obj_t *self; + if (MP_STATE_PORT(machine_i2s_obj[i2s_id]) == NULL) { + self = m_new_obj(machine_i2s_obj_t); + MP_STATE_PORT(machine_i2s_obj[i2s_id]) = self; + self->base.type = &machine_i2s_type; + self->i2s_id = i2s_id; + } else { + self = MP_STATE_PORT(machine_i2s_obj[i2s_id]); + machine_i2s_deinit(MP_OBJ_FROM_PTR(self)); + } + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args); + machine_i2s_init_helper(self, n_pos_args - 1, args + 1, &kw_args); + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_i2s_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_i2s_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + machine_i2s_deinit(MP_OBJ_FROM_PTR(self)); + machine_i2s_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_init_obj, 1, machine_i2s_init); + +STATIC mp_obj_t machine_i2s_deinit(mp_obj_t self_in) { + machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // use self->pio as in indication that I2S object has already been de-initialized + if (self->pio != NULL) { + pio_deinit(self); + dma_deinit(self); + irq_deinit(self); + m_free(self->ring_buffer_storage); + self->pio = NULL; // flag object as de-initialized + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2s_deinit_obj, machine_i2s_deinit); + +STATIC mp_obj_t machine_i2s_irq(mp_obj_t self_in, mp_obj_t handler) { + machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (handler != mp_const_none && !mp_obj_is_callable(handler)) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid callback")); + } + + if (handler != mp_const_none) { + self->io_mode = NON_BLOCKING; + } else { + self->io_mode = BLOCKING; + } + + self->callback_for_non_blocking = handler; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_i2s_irq_obj, machine_i2s_irq); + +// Shift() is typically used as a volume control. +// shift=1 increases volume by 6dB, shift=-1 decreases volume by 6dB +STATIC mp_obj_t machine_i2s_shift(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buf, ARG_bits, ARG_shift}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_bits, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_shift, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + }; + + // 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); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_RW); + + int16_t *buf_16 = bufinfo.buf; + int32_t *buf_32 = bufinfo.buf; + + uint8_t bits = args[ARG_bits].u_int; + int8_t shift = args[ARG_shift].u_int; + + uint32_t num_audio_samples; + switch (bits) { + case 16: + num_audio_samples = bufinfo.len / sizeof(uint16_t); + break; + + case 32: + num_audio_samples = bufinfo.len / sizeof(uint32_t); + break; + + default: + mp_raise_ValueError(MP_ERROR_TEXT("invalid bits")); + break; + } + + for (uint32_t i = 0; i < num_audio_samples; i++) { + switch (bits) { + case 16: + if (shift >= 0) { + buf_16[i] = buf_16[i] << shift; + } else { + buf_16[i] = buf_16[i] >> abs(shift); + } + break; + case 32: + if (shift >= 0) { + buf_32[i] = buf_32[i] << shift; + } else { + buf_32[i] = buf_32[i] >> abs(shift); + } + break; + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_shift_fun_obj, 0, machine_i2s_shift); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(machine_i2s_shift_obj, MP_ROM_PTR(&machine_i2s_shift_fun_obj)); + +STATIC const mp_rom_map_elem_t machine_i2s_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_i2s_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_i2s_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_i2s_irq_obj) }, + + // Static method + { MP_ROM_QSTR(MP_QSTR_shift), MP_ROM_PTR(&machine_i2s_shift_obj) }, + + // Constants + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_INT(RX) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_INT(TX) }, + { MP_ROM_QSTR(MP_QSTR_STEREO), MP_ROM_INT(STEREO) }, + { MP_ROM_QSTR(MP_QSTR_MONO), MP_ROM_INT(MONO) }, +}; +MP_DEFINE_CONST_DICT(machine_i2s_locals_dict, machine_i2s_locals_dict_table); + +STATIC mp_uint_t machine_i2s_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->mode != RX) { + *errcode = MP_EPERM; + return MP_STREAM_ERROR; + } + + uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1); + if (size % appbuf_sample_size_in_bytes != 0) { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } + + if (size == 0) { + return 0; + } + + if (self->io_mode == NON_BLOCKING) { + self->non_blocking_descriptor.appbuf.buf = (void *)buf_in; + self->non_blocking_descriptor.appbuf.len = size; + self->non_blocking_descriptor.index = 0; + self->non_blocking_descriptor.copy_in_progress = true; + return size; + } else { // blocking or uasyncio mode + mp_buffer_info_t appbuf; + appbuf.buf = (void *)buf_in; + appbuf.len = size; + uint32_t num_bytes_read = fill_appbuf_from_ringbuf(self, &appbuf); + return num_bytes_read; + } +} + +STATIC mp_uint_t machine_i2s_stream_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->mode != TX) { + *errcode = MP_EPERM; + return MP_STREAM_ERROR; + } + + if (size == 0) { + return 0; + } + + if (self->io_mode == NON_BLOCKING) { + self->non_blocking_descriptor.appbuf.buf = (void *)buf_in; + self->non_blocking_descriptor.appbuf.len = size; + self->non_blocking_descriptor.index = 0; + self->non_blocking_descriptor.copy_in_progress = true; + return size; + } else { // blocking or uasyncio mode + mp_buffer_info_t appbuf; + appbuf.buf = (void *)buf_in; + appbuf.len = size; + uint32_t num_bytes_written = copy_appbuf_to_ringbuf(self, &appbuf); + return num_bytes_written; + } +} + +STATIC mp_uint_t machine_i2s_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_uint_t ret; + uintptr_t flags = arg; + self->io_mode = UASYNCIO; // a call to ioctl() is an indication that uasyncio is being used + + if (request == MP_STREAM_POLL) { + ret = 0; + + if (flags & MP_STREAM_POLL_RD) { + if (self->mode != RX) { + *errcode = MP_EPERM; + return MP_STREAM_ERROR; + } + + if (!ringbuf_is_empty(&self->ring_buffer)) { + ret |= MP_STREAM_POLL_RD; + } + } + + if (flags & MP_STREAM_POLL_WR) { + if (self->mode != TX) { + *errcode = MP_EPERM; + return MP_STREAM_ERROR; + } + + if (!ringbuf_is_full(&self->ring_buffer)) { + ret |= MP_STREAM_POLL_WR; + } + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + + return ret; +} + +STATIC const mp_stream_p_t i2s_stream_p = { + .read = machine_i2s_stream_read, + .write = machine_i2s_stream_write, + .ioctl = machine_i2s_ioctl, + .is_text = false, +}; + +const mp_obj_type_t machine_i2s_type = { + { &mp_type_type }, + .name = MP_QSTR_I2S, + .print = machine_i2s_print, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &i2s_stream_p, + .make_new = machine_i2s_make_new, + .locals_dict = (mp_obj_dict_t *)&machine_i2s_locals_dict, +}; diff --git a/ports/rp2/machine_pwm.c b/ports/rp2/machine_pwm.c index ff40c5503..41dc3ab47 100644 --- a/ports/rp2/machine_pwm.c +++ b/ports/rp2/machine_pwm.c @@ -34,40 +34,49 @@ /******************************************************************************/ // MicroPython bindings for machine.PWM -const mp_obj_type_t machine_pwm_type; - typedef struct _machine_pwm_obj_t { mp_obj_base_t base; uint8_t slice; uint8_t channel; + uint8_t duty_type; + mp_int_t duty; } machine_pwm_obj_t; -STATIC machine_pwm_obj_t machine_pwm_obj[] = { - {{&machine_pwm_type}, 0, PWM_CHAN_A}, - {{&machine_pwm_type}, 0, PWM_CHAN_B}, - {{&machine_pwm_type}, 1, PWM_CHAN_A}, - {{&machine_pwm_type}, 1, PWM_CHAN_B}, - {{&machine_pwm_type}, 2, PWM_CHAN_A}, - {{&machine_pwm_type}, 2, PWM_CHAN_B}, - {{&machine_pwm_type}, 3, PWM_CHAN_A}, - {{&machine_pwm_type}, 3, PWM_CHAN_B}, - {{&machine_pwm_type}, 4, PWM_CHAN_A}, - {{&machine_pwm_type}, 4, PWM_CHAN_B}, - {{&machine_pwm_type}, 5, PWM_CHAN_A}, - {{&machine_pwm_type}, 5, PWM_CHAN_B}, - {{&machine_pwm_type}, 6, PWM_CHAN_A}, - {{&machine_pwm_type}, 6, PWM_CHAN_B}, - {{&machine_pwm_type}, 7, PWM_CHAN_A}, - {{&machine_pwm_type}, 7, PWM_CHAN_B}, +enum { + DUTY_NOT_SET = 0, + DUTY_U16, + DUTY_NS }; -STATIC void machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { +STATIC machine_pwm_obj_t machine_pwm_obj[] = { + {{&machine_pwm_type}, 0, PWM_CHAN_A, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 0, PWM_CHAN_B, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 1, PWM_CHAN_A, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 1, PWM_CHAN_B, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 2, PWM_CHAN_A, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 2, PWM_CHAN_B, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 3, PWM_CHAN_A, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 3, PWM_CHAN_B, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 4, PWM_CHAN_A, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 4, PWM_CHAN_B, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 5, PWM_CHAN_A, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 5, PWM_CHAN_B, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 6, PWM_CHAN_A, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 6, PWM_CHAN_B, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 7, PWM_CHAN_A, DUTY_NOT_SET, 0}, + {{&machine_pwm_type}, 7, PWM_CHAN_B, DUTY_NOT_SET, 0}, +}; + +STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16); +STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns); + +STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "", self->slice, self->channel); } // PWM(pin) -STATIC mp_obj_t machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { +STATIC mp_obj_t mp_machine_pwm_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); @@ -77,7 +86,8 @@ STATIC mp_obj_t machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, s // Get static peripheral object. uint slice = pwm_gpio_to_slice_num(gpio); uint8_t channel = pwm_gpio_to_channel(gpio); - const machine_pwm_obj_t *self = &machine_pwm_obj[slice * 2 + channel]; + machine_pwm_obj_t *self = &machine_pwm_obj[slice * 2 + channel]; + self->duty_type = DUTY_NOT_SET; // Select PWM function for given GPIO. gpio_set_function(gpio, GPIO_FUNC_PWM); @@ -85,113 +95,88 @@ STATIC mp_obj_t machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, s return MP_OBJ_FROM_PTR(self); } -STATIC mp_obj_t machine_pwm_deinit(mp_obj_t self_in) { - machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); +STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) { + self->duty_type = DUTY_NOT_SET; pwm_set_enabled(self->slice, false); - return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_deinit_obj, machine_pwm_deinit); -// PWM.freq([value]) -STATIC mp_obj_t machine_pwm_freq(size_t n_args, const mp_obj_t *args) { - machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); +STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) { uint32_t source_hz = clock_get_hz(clk_sys); - if (n_args == 1) { - // Get frequency. - uint32_t div16 = pwm_hw->slice[self->slice].div; - uint32_t top = pwm_hw->slice[self->slice].top; - uint32_t pwm_freq = 16 * source_hz / div16 / top; - return MP_OBJ_NEW_SMALL_INT(pwm_freq); - } else { - // Set the frequency, making "top" as large as possible for maximum resolution. - // Maximum "top" is set at 65534 to be able to achieve 100% duty with 65535. - #define TOP_MAX 65534 - mp_int_t freq = mp_obj_get_int(args[1]); - uint32_t div16_top = 16 * source_hz / freq; - uint32_t top = 1; - for (;;) { - // Try a few small prime factors to get close to the desired frequency. - if (div16_top >= 16 * 5 && div16_top % 5 == 0 && top * 5 <= TOP_MAX) { - div16_top /= 5; - top *= 5; - } else if (div16_top >= 16 * 3 && div16_top % 3 == 0 && top * 3 <= TOP_MAX) { - div16_top /= 3; - top *= 3; - } else if (div16_top >= 16 * 2 && top * 2 <= TOP_MAX) { - div16_top /= 2; - top *= 2; - } else { - break; - } - } - if (div16_top < 16) { - mp_raise_ValueError(MP_ERROR_TEXT("freq too large")); - } else if (div16_top >= 256 * 16) { - mp_raise_ValueError(MP_ERROR_TEXT("freq too small")); - } - pwm_hw->slice[self->slice].div = div16_top; - pwm_hw->slice[self->slice].top = top; - return mp_const_none; - } -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_freq_obj, 1, 2, machine_pwm_freq); - -// PWM.duty_u16([value]) -STATIC mp_obj_t machine_pwm_duty_u16(size_t n_args, const mp_obj_t *args) { - machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + uint32_t div16 = pwm_hw->slice[self->slice].div; uint32_t top = pwm_hw->slice[self->slice].top; - if (n_args == 1) { - // Get duty cycle. - uint32_t cc = pwm_hw->slice[self->slice].cc; - cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff; - return MP_OBJ_NEW_SMALL_INT(cc * 65535 / (top + 1)); - } else { - // Set duty cycle. - mp_int_t duty_u16 = mp_obj_get_int(args[1]); - uint32_t cc = duty_u16 * (top + 1) / 65535; - pwm_set_chan_level(self->slice, self->channel, cc); - pwm_set_enabled(self->slice, true); - return mp_const_none; + uint32_t pwm_freq = 16 * source_hz / div16 / (top + 1); + return MP_OBJ_NEW_SMALL_INT(pwm_freq); +} + +STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) { + // Set the frequency, making "top" as large as possible for maximum resolution. + // Maximum "top" is set at 65534 to be able to achieve 100% duty with 65535. + #define TOP_MAX 65534 + uint32_t source_hz = clock_get_hz(clk_sys); + uint32_t div16_top = 16 * source_hz / freq; + uint32_t top = 1; + for (;;) { + // Try a few small prime factors to get close to the desired frequency. + if (div16_top >= 16 * 5 && div16_top % 5 == 0 && top * 5 <= TOP_MAX) { + div16_top /= 5; + top *= 5; + } else if (div16_top >= 16 * 3 && div16_top % 3 == 0 && top * 3 <= TOP_MAX) { + div16_top /= 3; + top *= 3; + } else if (div16_top >= 16 * 2 && top * 2 <= TOP_MAX) { + div16_top /= 2; + top *= 2; + } else { + break; + } + } + if (div16_top < 16) { + mp_raise_ValueError(MP_ERROR_TEXT("freq too large")); + } else if (div16_top >= 256 * 16) { + mp_raise_ValueError(MP_ERROR_TEXT("freq too small")); + } + pwm_hw->slice[self->slice].div = div16_top; + pwm_hw->slice[self->slice].top = top - 1; + if (self->duty_type == DUTY_U16) { + mp_machine_pwm_duty_set_u16(self, self->duty); + } else if (self->duty_type == DUTY_NS) { + mp_machine_pwm_duty_set_ns(self, self->duty); } } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_u16_obj, 1, 2, machine_pwm_duty_u16); -// PWM.duty_ns([value]) -STATIC mp_obj_t machine_pwm_duty_ns(size_t n_args, const mp_obj_t *args) { - machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); +STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) { + uint32_t top = pwm_hw->slice[self->slice].top; + uint32_t cc = pwm_hw->slice[self->slice].cc; + cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff; + return MP_OBJ_NEW_SMALL_INT(cc * 65535 / (top + 1)); +} + +STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16) { + uint32_t top = pwm_hw->slice[self->slice].top; + uint32_t cc = duty_u16 * (top + 1) / 65535; + pwm_set_chan_level(self->slice, self->channel, cc); + pwm_set_enabled(self->slice, true); + self->duty = duty_u16; + self->duty_type = DUTY_U16; +} + +STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) { uint32_t source_hz = clock_get_hz(clk_sys); uint32_t slice_hz = 16 * source_hz / pwm_hw->slice[self->slice].div; - if (n_args == 1) { - // Get duty cycle. - uint32_t cc = pwm_hw->slice[self->slice].cc; - cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff; - return MP_OBJ_NEW_SMALL_INT((uint64_t)cc * 1000000000ULL / slice_hz); - } else { - // Set duty cycle. - mp_int_t duty_ns = mp_obj_get_int(args[1]); - uint32_t cc = (uint64_t)duty_ns * slice_hz / 1000000000ULL; - if (cc > 65535) { - mp_raise_ValueError(MP_ERROR_TEXT("duty larger than period")); - } - pwm_set_chan_level(self->slice, self->channel, cc); - pwm_set_enabled(self->slice, true); - return mp_const_none; - } + uint32_t cc = pwm_hw->slice[self->slice].cc; + cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff; + return MP_OBJ_NEW_SMALL_INT((uint64_t)cc * 1000000000ULL / slice_hz); } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_ns_obj, 1, 2, machine_pwm_duty_ns); -STATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_pwm_freq_obj) }, - { MP_ROM_QSTR(MP_QSTR_duty_u16), MP_ROM_PTR(&machine_pwm_duty_u16_obj) }, - { MP_ROM_QSTR(MP_QSTR_duty_ns), MP_ROM_PTR(&machine_pwm_duty_ns_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict, machine_pwm_locals_dict_table); - -const mp_obj_type_t machine_pwm_type = { - { &mp_type_type }, - .name = MP_QSTR_PWM, - .print = machine_pwm_print, - .make_new = machine_pwm_make_new, - .locals_dict = (mp_obj_dict_t *)&machine_pwm_locals_dict, -}; +STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns) { + uint32_t source_hz = clock_get_hz(clk_sys); + uint32_t slice_hz = 16 * source_hz / pwm_hw->slice[self->slice].div; + uint32_t cc = (uint64_t)duty_ns * slice_hz / 1000000000ULL; + if (cc > 65535) { + mp_raise_ValueError(MP_ERROR_TEXT("duty larger than period")); + } + pwm_set_chan_level(self->slice, self->channel, cc); + pwm_set_enabled(self->slice, true); + self->duty = duty_ns; + self->duty_type = DUTY_NS; +} diff --git a/ports/rp2/machine_uart.c b/ports/rp2/machine_uart.c index a8ec149f4..887954276 100644 --- a/ports/rp2/machine_uart.c +++ b/ports/rp2/machine_uart.c @@ -126,7 +126,7 @@ STATIC void uart_fill_tx_fifo(machine_uart_obj_t *self) { } STATIC inline void uart_service_interrupt(machine_uart_obj_t *self) { - if (uart_get_hw(self->uart)->mis & UART_UARTMIS_RXMIS_BITS) { // rx interrupt? + if (uart_get_hw(self->uart)->mis & (UART_UARTMIS_RXMIS_BITS | UART_UARTMIS_RTMIS_BITS)) { // rx interrupt? // clear all interrupt bits but tx uart_get_hw(self->uart)->icr = UART_UARTICR_BITS & (~UART_UARTICR_TXIC_BITS); if (!self->read_lock) { diff --git a/ports/rp2/main.c b/ports/rp2/main.c index d0b89c8d6..84f23af23 100644 --- a/ports/rp2/main.c +++ b/ports/rp2/main.c @@ -32,6 +32,8 @@ #include "py/mperrno.h" #include "py/mphal.h" #include "py/stackctrl.h" +#include "extmod/modbluetooth.h" +#include "extmod/modnetwork.h" #include "shared/readline/readline.h" #include "shared/runtime/gchelper.h" #include "shared/runtime/pyexec.h" @@ -39,6 +41,7 @@ #include "uart.h" #include "modmachine.h" #include "modrp2.h" +#include "mpbthciport.h" #include "genhdr/mpversion.h" #include "pico/stdlib.h" @@ -97,15 +100,20 @@ int main(int argc, char **argv) { // Initialise MicroPython runtime. 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_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); - mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); // Initialise sub-systems. readline_init0(); machine_pin_init(); rp2_pio_init(); + machine_i2s_init0(); + + #if MICROPY_PY_BLUETOOTH + mp_bluetooth_hci_init(); + #endif + #if MICROPY_PY_NETWORK + mod_network_init(); + #endif // Execute _boot.py to set up the filesystem. pyexec_frozen_module("_boot.py"); @@ -136,7 +144,13 @@ int main(int argc, char **argv) { soft_reset_exit: mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n"); + #if MICROPY_PY_NETWORK + mod_network_deinit(); + #endif rp2_pio_deinit(); + #if MICROPY_PY_BLUETOOTH + mp_bluetooth_deinit(); + #endif machine_pin_deinit(); #if MICROPY_PY_THREAD mp_thread_deinit(); diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 1b2b2adad..9d6178a0f 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -27,9 +27,11 @@ #include "py/runtime.h" #include "py/mphal.h" #include "shared/runtime/pyexec.h" +#include "extmod/machine_bitstream.h" #include "extmod/machine_i2c.h" #include "extmod/machine_mem.h" #include "extmod/machine_pulse.h" +#include "extmod/machine_pwm.h" #include "extmod/machine_signal.h" #include "extmod/machine_spi.h" @@ -85,7 +87,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader); STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { - return MP_OBJ_NEW_SMALL_INT(clock_get_hz(clk_sys)); + return MP_OBJ_NEW_SMALL_INT(mp_hal_get_cpu_freq()); } else { mp_int_t freq = mp_obj_get_int(args[0]); if (!set_sys_clock_khz(freq / 1000, false)) { @@ -153,6 +155,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + #if MICROPY_PY_MACHINE_BITSTREAM + { MP_ROM_QSTR(MP_QSTR_bitstream), MP_ROM_PTR(&machine_bitstream_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, @@ -162,6 +167,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_hw_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) }, + { MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&machine_i2s_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) }, { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, diff --git a/ports/rp2/modmachine.h b/ports/rp2/modmachine.h index c79bcfdad..af02cd193 100644 --- a/ports/rp2/modmachine.h +++ b/ports/rp2/modmachine.h @@ -5,8 +5,8 @@ extern const mp_obj_type_t machine_adc_type; extern const mp_obj_type_t machine_hw_i2c_type; +extern const mp_obj_type_t machine_i2s_type; extern const mp_obj_type_t machine_pin_type; -extern const mp_obj_type_t machine_pwm_type; extern const mp_obj_type_t machine_rtc_type; extern const mp_obj_type_t machine_spi_type; extern const mp_obj_type_t machine_timer_type; @@ -15,5 +15,6 @@ extern const mp_obj_type_t machine_wdt_type; void machine_pin_init(void); void machine_pin_deinit(void); +void machine_i2s_init0(void); #endif // MICROPY_INCLUDED_RP2_MODMACHINE_H diff --git a/ports/rp2/modrp2.c b/ports/rp2/modrp2.c index 8009fa33f..15c61911d 100644 --- a/ports/rp2/modrp2.c +++ b/ports/rp2/modrp2.c @@ -25,6 +25,7 @@ */ #include "py/runtime.h" +#include "drivers/dht/dht.h" #include "modrp2.h" STATIC const mp_rom_map_elem_t rp2_module_globals_table[] = { @@ -32,6 +33,8 @@ STATIC const mp_rom_map_elem_t rp2_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&rp2_flash_type) }, { MP_ROM_QSTR(MP_QSTR_PIO), MP_ROM_PTR(&rp2_pio_type) }, { MP_ROM_QSTR(MP_QSTR_StateMachine), MP_ROM_PTR(&rp2_state_machine_type) }, + + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, }; STATIC MP_DEFINE_CONST_DICT(rp2_module_globals, rp2_module_globals_table); diff --git a/ports/rp2/modules/rp2.py b/ports/rp2/modules/rp2.py index c7e4d1fdd..1e4bb26cf 100644 --- a/ports/rp2/modules/rp2.py +++ b/ports/rp2/modules/rp2.py @@ -88,6 +88,10 @@ class PIOASMEmit: def side(self, value): self.num_sideset += 1 if self.pass_ > 0: + if self.sideset_count == 0: + raise PIOASMError("no sideset") + elif value >= (1 << self.sideset_count): + raise PIOASMError("sideset too large") set_bit = 13 - self.sideset_count self.prog[_PROG_DATA][-1] |= self.sideset_opt << 12 | value << set_bit return self @@ -269,17 +273,17 @@ def asm_pio(**kw): # sideset_count is inclusive of enable bit -def asm_pio_encode(instr, sideset_count): +def asm_pio_encode(instr, sideset_count, sideset_opt=False): emit = PIOASMEmit() - emit.delay_max = 31 emit.sideset_count = sideset_count - if emit.sideset_count: - emit.delay_max >>= emit.sideset_count + emit.sideset_opt = sideset_opt != 0 + emit.delay_max = 31 >> (emit.sideset_count + emit.sideset_opt) emit.pass_ = 1 emit.num_instr = 0 emit.num_sideset = 0 gl = _pio_funcs + gl["word"] = emit.word gl["nop"] = emit.nop # gl["jmp"] = emit.jmp currently not supported gl["wait"] = emit.wait diff --git a/ports/rp2/mpbthciport.c b/ports/rp2/mpbthciport.c new file mode 100644 index 000000000..58639fd5b --- /dev/null +++ b/ports/rp2/mpbthciport.c @@ -0,0 +1,200 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Ibrahim Abdelkader + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "extmod/modbluetooth.h" +#include "extmod/mpbthci.h" +#include "modmachine.h" +#include "mpbthciport.h" +#include "pico/stdlib.h" + +#if MICROPY_PY_BLUETOOTH + +#define debug_printf(...) // mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) +#define error_printf(...) mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) + +// Poll timer ID. +static alarm_id_t poll_timer_id = 0; + +uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; + +// Prevent double-enqueuing of the scheduled task. +STATIC volatile bool events_task_is_scheduled; + +void mp_bluetooth_hci_init(void) { + events_task_is_scheduled = false; +} + +STATIC void mp_bluetooth_hci_start_polling(void) { + events_task_is_scheduled = false; + mp_bluetooth_hci_poll_now(); +} + +static int64_t mp_bluetooth_hci_timer_callback(alarm_id_t id, void *user_data) { + poll_timer_id = 0; + mp_bluetooth_hci_poll_now(); + return 0; +} + +void mp_bluetooth_hci_poll_in_ms(uint32_t ms) { + poll_timer_id = add_alarm_in_ms(ms, mp_bluetooth_hci_timer_callback, NULL, true); +} + +// For synchronous mode, we run all BLE stack code inside a scheduled task. +// This task is scheduled periodically via a timer, or immediately after UART RX IRQ. +STATIC mp_obj_t run_events_scheduled_task(mp_obj_t none_in) { + (void)none_in; + events_task_is_scheduled = false; + // This will process all buffered HCI UART data, and run any callouts or events. + mp_bluetooth_hci_poll(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_scheduled_task); + +// Called periodically (systick) or directly (e.g. UART RX IRQ) in order to +// request that processing happens ASAP in the scheduler. +void mp_bluetooth_hci_poll_now(void) { + if (!events_task_is_scheduled) { + events_task_is_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&run_events_scheduled_task_obj), mp_const_none); + if (!events_task_is_scheduled) { + // The schedule queue is full, set callback to try again soon. + mp_bluetooth_hci_poll_in_ms(5); + } + } +} + +mp_obj_t mp_bthci_uart; + +int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) { + debug_printf("mp_bluetooth_hci_uart_init\n"); + + mp_obj_t args[] = { + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_BLE_UART_ID), + MP_OBJ_NEW_SMALL_INT(MICROPY_HW_BLE_UART_BAUDRATE), + MP_OBJ_NEW_QSTR(MP_QSTR_flow), MP_OBJ_NEW_SMALL_INT((1 | 2)), + MP_OBJ_NEW_QSTR(MP_QSTR_timeout), MP_OBJ_NEW_SMALL_INT(1000), + }; + + mp_bthci_uart = machine_uart_type.make_new((mp_obj_t)&machine_uart_type, 2, 2, args); + MP_STATE_PORT(mp_bthci_uart) = mp_bthci_uart; + + // Start the HCI polling to process any initial events/packets. + mp_bluetooth_hci_start_polling(); + return 0; +} + +int mp_bluetooth_hci_uart_deinit(void) { + debug_printf("mp_bluetooth_hci_uart_deinit\n"); + + // If a poll callback is set cancel it now. + if (poll_timer_id > 0) { + cancel_alarm(poll_timer_id); + } + poll_timer_id = 0; + return 0; +} + +int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) { + debug_printf("mp_bluetooth_hci_uart_set_baudrate(%lu)\n", baudrate); + return 0; +} + +int mp_bluetooth_hci_uart_any(void) { + int errcode = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)machine_uart_type.protocol; + + mp_uint_t ret = proto->ioctl(mp_bthci_uart, MP_STREAM_POLL, MP_STREAM_POLL_RD, &errcode); + if (errcode != 0) { + error_printf("Uart ioctl failed to poll UART %d\n", errcode); + return -1; + } + return ret & MP_STREAM_POLL_RD; +} + +int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) { + debug_printf("mp_bluetooth_hci_uart_write\n"); + + int errcode = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)machine_uart_type.protocol; + + mp_bluetooth_hci_controller_wakeup(); + + if (proto->write(mp_bthci_uart, (void *)buf, len, &errcode) < 0) { + error_printf("mp_bluetooth_hci_uart_write: failed to write to UART %d\n", errcode); + } + return 0; +} + +// This function expects the controller to be in the wake state via a previous call +// to mp_bluetooth_hci_controller_woken. +int mp_bluetooth_hci_uart_readchar(void) { + debug_printf("mp_bluetooth_hci_uart_readchar\n"); + if (mp_bluetooth_hci_uart_any()) { + int errcode = 0; + uint8_t buf = 0; + const mp_stream_p_t *proto = (mp_stream_p_t *)machine_uart_type.protocol; + if (proto->read(mp_bthci_uart, (void *)&buf, 1, &errcode) < 0) { + error_printf("mp_bluetooth_hci_uart_readchar: failed to read UART %d\n", errcode); + return -1; + } + return buf; + } else { + debug_printf("mp_bluetooth_hci_uart_readchar: not ready\n"); + return -1; + } +} + +// Default (weak) implementation of the HCI controller interface. +// A driver (e.g. cywbt43.c) can override these for controller-specific +// functionality (i.e. power management). +MP_WEAK int mp_bluetooth_hci_controller_init(void) { + debug_printf("mp_bluetooth_hci_controller_init (default)\n"); + return 0; +} + +MP_WEAK int mp_bluetooth_hci_controller_deinit(void) { + debug_printf("mp_bluetooth_hci_controller_deinit (default)\n"); + return 0; +} + +MP_WEAK int mp_bluetooth_hci_controller_sleep_maybe(void) { + debug_printf("mp_bluetooth_hci_controller_sleep_maybe (default)\n"); + return 0; +} + +MP_WEAK bool mp_bluetooth_hci_controller_woken(void) { + debug_printf("mp_bluetooth_hci_controller_woken (default)\n"); + return true; +} + +MP_WEAK int mp_bluetooth_hci_controller_wakeup(void) { + debug_printf("mp_bluetooth_hci_controller_wakeup (default)\n"); + return 0; +} + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/rp2/mpbthciport.h b/ports/rp2/mpbthciport.h new file mode 100644 index 000000000..ac5263aa1 --- /dev/null +++ b/ports/rp2/mpbthciport.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_RP2_MPBTHCIPORT_H +#define MICROPY_INCLUDED_RP2_MPBTHCIPORT_H + +// Initialise the HCI subsystem (should be called once, early on). +void mp_bluetooth_hci_init(void); + +// Poll the HCI now, or after a certain timeout. +void mp_bluetooth_hci_poll_now(void); +void mp_bluetooth_hci_poll_in_ms(uint32_t ms); + +// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c). +// Request new data from the uart and pass to the stack, and run pending events/callouts. +// This is a low-level function and should not be called directly, use +// mp_bluetooth_hci_poll_now/mp_bluetooth_hci_poll_in_ms instead. +void mp_bluetooth_hci_poll(void); + +#endif // MICROPY_INCLUDED_RP2_MPBTHCIPORT_H diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index f95d6a470..5f563bf99 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -41,6 +41,10 @@ #define MICROPY_HW_ENABLE_UART_REPL (0) // useful if there is no USB #define MICROPY_HW_ENABLE_USBDEV (1) +#ifndef MICROPY_CONFIG_ROM_LEVEL +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) +#endif + // Memory allocation policies #define MICROPY_GC_STACK_ENTRY_TYPE uint16_t #define MICROPY_ALLOC_PATH_MAX (128) @@ -54,91 +58,49 @@ #define MICROPY_EMIT_INLINE_THUMB_FLOAT (0) #define MICROPY_EMIT_INLINE_THUMB_ARMV7M (0) +// Optimisations +#define MICROPY_OPT_COMPUTED_GOTO (1) + +// Features currently overriden for rp2, planned to be brought in line with +// other ports +#define MICROPY_PY_BUILTINS_EXECFILE (0) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (0) +#define MICROPY_REPL_EMACS_KEYS (0) + // Python internal features #define MICROPY_READER_VFS (1) #define MICROPY_ENABLE_GC (1) -#define MICROPY_ENABLE_FINALISER (1) -#define MICROPY_STACK_CHECK (1) #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) -#define MICROPY_KBD_EXCEPTION (1) -#define MICROPY_HELPER_REPL (1) -#define MICROPY_REPL_AUTO_INDENT (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) -#define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) -#define MICROPY_STREAMS_NON_BLOCK (1) -#define MICROPY_MODULE_BUILTIN_INIT (1) -#define MICROPY_MODULE_WEAK_LINKS (1) -#define MICROPY_CAN_OVERRIDE_BUILTINS (1) -#define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_SCHEDULER_DEPTH (8) // Fine control over Python builtins, classes, modules, etc -#define MICROPY_PY_FUNCTION_ATTRS (1) -#define MICROPY_PY_DESCRIPTORS (1) -#define MICROPY_PY_DELATTR_SETATTR (1) -#define MICROPY_PY_FSTRINGS (1) -#define MICROPY_PY_BUILTINS_STR_UNICODE (1) -#define MICROPY_PY_BUILTINS_STR_CENTER (1) -#define MICROPY_PY_BUILTINS_STR_PARTITION (1) -#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) -#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) -#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) -#define MICROPY_PY_BUILTINS_SLICE_INDICES (1) -#define MICROPY_PY_BUILTINS_FROZENSET (1) -#define MICROPY_PY_BUILTINS_ROUND_INT (1) -#define MICROPY_PY_ALL_SPECIAL_METHODS (1) -#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) -#define MICROPY_PY_BUILTINS_COMPILE (1) -#define MICROPY_PY_BUILTINS_INPUT (1) -#define MICROPY_PY_BUILTINS_POW3 (1) -#define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_TEXT rp2_help_text -#define MICROPY_PY_BUILTINS_HELP_MODULES (1) -#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) -#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) -#define MICROPY_PY_COLLECTIONS_DEQUE (1) -#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) -#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) -#define MICROPY_PY_MATH_FACTORIAL (1) -#define MICROPY_PY_MATH_ISCLOSE (1) -#define MICROPY_PY_CMATH (1) -#define MICROPY_PY_IO_IOBASE (1) -#define MICROPY_PY_IO_FILEIO (1) -#define MICROPY_PY_SYS_MAXSIZE (1) -#define MICROPY_PY_SYS_STDFILES (1) -#define MICROPY_PY_SYS_STDIO_BUFFER (1) #define MICROPY_PY_SYS_PLATFORM "rp2" -#define MICROPY_PY_UERRNO (1) #define MICROPY_PY_THREAD (1) #define MICROPY_PY_THREAD_GIL (0) // Extended modules #define MICROPY_EPOCH_IS_1970 (1) -#define MICROPY_PY_UASYNCIO (1) -#define MICROPY_PY_UCTYPES (1) -#define MICROPY_PY_UZLIB (1) -#define MICROPY_PY_UJSON (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 (1) -#define MICROPY_PY_UHASHLIB (1) -#define MICROPY_PY_UBINASCII (1) -#define MICROPY_PY_UBINASCII_CRC32 (1) #define MICROPY_PY_UTIME_MP_HAL (1) -#define MICROPY_PY_URANDOM (1) -#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) #define MICROPY_PY_URANDOM_SEED_INIT_FUNC (rosc_random_u32()) -#define MICROPY_PY_USELECT (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_PY_MACHINE_BITSTREAM (1) #define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_PWM (1) +#define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS (1) +#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/rp2/machine_pwm.c" #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SOFTI2C (1) #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (SPI_MSB_FIRST) #define MICROPY_PY_MACHINE_SPI_LSB (SPI_LSB_FIRST) -#define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_MACHINE_SOFTSPI (1) +#define MICROPY_PY_ONEWIRE (1) #define MICROPY_VFS (1) #define MICROPY_VFS_LFS2 (1) #define MICROPY_VFS_FAT (1) @@ -162,9 +124,11 @@ { 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_network; extern const struct _mp_obj_module_t mp_module_onewire; extern const struct _mp_obj_module_t mp_module_rp2; extern const struct _mp_obj_module_t mp_module_uos; +extern const struct _mp_obj_module_t mp_module_usocket; extern const struct _mp_obj_module_t mp_module_utime; extern const struct _mp_obj_module_t mp_module_lvgl; extern const struct _mp_obj_module_t mp_module_lodepng; @@ -183,6 +147,47 @@ extern const struct _mp_obj_module_t mp_module_lodepng; #define MICROPY_PORT_LODEPNG_DEF #endif +#if MICROPY_PY_USOCKET +#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, +#else +#define SOCKET_BUILTIN_MODULE +#endif +#if MICROPY_PY_NETWORK +#define NETWORK_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) }, +#define NETWORK_ROOT_POINTERS mp_obj_list_t mod_network_nic_list; +#else +#define NETWORK_BUILTIN_MODULE +#define NETWORK_ROOT_POINTERS +#endif + +#if MICROPY_PY_BLUETOOTH +#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH struct _machine_uart_obj_t *mp_bthci_uart; +#else +#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH +#endif + +#if MICROPY_BLUETOOTH_NIMBLE +struct _mp_bluetooth_nimble_root_pointers_t; +struct _mp_bluetooth_nimble_malloc_t; +#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE struct _mp_bluetooth_nimble_malloc_t *bluetooth_nimble_memory; struct _mp_bluetooth_nimble_root_pointers_t *bluetooth_nimble_root_pointers; +#else +#define MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE +#endif + +#if MICROPY_PY_NETWORK_NINAW10 +// This Network interface requires the extended socket state. +#ifndef MICROPY_PY_USOCKET_EXTENDED_STATE +#define MICROPY_PY_USOCKET_EXTENDED_STATE (1) +#endif +// It also requires an additional root pointer for the SPI object. +#define MICROPY_PORT_ROOT_POINTER_NINAW10 struct _machine_spi_obj_t *mp_wifi_spi; +extern const struct _mod_network_nic_type_t mod_network_nic_type_nina; +#define MICROPY_HW_NIC_NINAW10 { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_nic_type_nina) }, +#else +#define MICROPY_HW_NIC_NINAW10 +#define MICROPY_PORT_ROOT_POINTER_NINAW10 +#endif + #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \ { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \ @@ -191,6 +196,8 @@ extern const struct _mp_obj_module_t mp_module_lodepng; { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ MICROPY_PORT_LVGL_DEF \ MICROPY_PORT_LODEPNG_DEF \ + SOCKET_BUILTIN_MODULE \ + NETWORK_BUILTIN_MODULE \ #if MICROPY_PY_LVGL #ifndef MICROPY_INCLUDED_PY_MPSTATE_H @@ -204,6 +211,9 @@ extern const struct _mp_obj_module_t mp_module_lodepng; #define LV_ROOTS #endif +#define MICROPY_PORT_NETWORK_INTERFACES \ + MICROPY_HW_NIC_NINAW10 \ + #ifndef MICROPY_BOARD_ROOT_POINTERS #define MICROPY_BOARD_ROOT_POINTERS #endif @@ -217,7 +227,12 @@ extern const struct _mp_obj_module_t mp_module_lodepng; void *rp2_state_machine_irq_obj[8]; \ void *rp2_uart_rx_buffer[2]; \ void *rp2_uart_tx_buffer[2]; \ + void *machine_i2s_obj[2]; \ + NETWORK_ROOT_POINTERS \ MICROPY_BOARD_ROOT_POINTERS \ + MICROPY_PORT_ROOT_POINTER_NINAW10 \ + MICROPY_PORT_ROOT_POINTER_BLUETOOTH \ + MICROPY_PORT_ROOT_POINTER_BLUETOOTH_NIMBLE \ #define MP_STATE_PORT MP_STATE_VM diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h index 40633dcf2..458d9a9a1 100644 --- a/ports/rp2/mphalport.h +++ b/ports/rp2/mphalport.h @@ -28,6 +28,10 @@ #include "py/mpconfig.h" #include "py/ringbuf.h" #include "pico/time.h" +#include "hardware/clocks.h" +#include "hardware/structs/systick.h" + +#define SYSTICK_MAX (0xffffff) extern int mp_interrupt_char; extern ringbuf_t stdin_ringbuf; @@ -59,6 +63,10 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { return time_us_32(); } +static inline mp_uint_t mp_hal_get_cpu_freq(void) { + return clock_get_hz(clk_sys); +} + // C-level pin HAL #include "py/obj.h" @@ -110,4 +118,12 @@ static inline void mp_hal_pin_od_high(mp_hal_pin_obj_t pin) { gpio_set_dir(pin, GPIO_IN); } +static inline void mp_hal_pin_low(mp_hal_pin_obj_t pin) { + gpio_clr_mask(1 << pin); +} + +static inline void mp_hal_pin_high(mp_hal_pin_obj_t pin) { + gpio_set_mask(1 << pin); +} + #endif // MICROPY_INCLUDED_RP2_MPHALPORT_H diff --git a/ports/rp2/mpnimbleport.c b/ports/rp2/mpnimbleport.c new file mode 100644 index 000000000..74e9ecb02 --- /dev/null +++ b/ports/rp2/mpnimbleport.c @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Jim Mussared + * 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/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/stream.h" + +#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE + +#define DEBUG_printf(...) // printf("mpnimbleport.c: " __VA_ARGS__) + +#include "host/ble_hs.h" +#include "nimble/nimble_npl.h" + +#include "extmod/modbluetooth.h" +#include "extmod/mpbthci.h" +#include "extmod/nimble/modbluetooth_nimble.h" +#include "extmod/nimble/hal/hal_uart.h" +#include "mpbthciport.h" + +// Get any pending data from the UART and send it to NimBLE's HCI buffers. +// Any further processing by NimBLE will be run via its event queue. +void mp_bluetooth_hci_poll(void) { + if (mp_bluetooth_nimble_ble_state >= MP_BLUETOOTH_NIMBLE_BLE_STATE_WAITING_FOR_SYNC) { + // DEBUG_printf("mp_bluetooth_hci_poll_uart %d\n", mp_bluetooth_nimble_ble_state); + + // Run any timers. + mp_bluetooth_nimble_os_callout_process(); + + // Process incoming UART data, and run events as they are generated. + mp_bluetooth_nimble_hci_uart_process(true); + + // Run any remaining events (e.g. if there was no UART data). + mp_bluetooth_nimble_os_eventq_run_all(); + } + + if (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { + // Call this function again in 128ms to check for new events. + // TODO: improve this by only calling back when needed. + mp_bluetooth_hci_poll_in_ms(128); + } +} + +// --- Port-specific helpers for the generic NimBLE bindings. ----------------- + +void mp_bluetooth_nimble_hci_uart_wfi(void) { + #if defined(__WFI) + __WFI(); + #endif + // This is called while NimBLE is waiting in ble_npl_sem_pend, i.e. waiting for an HCI ACK. + // Do not need to run events here (it must not invoke Python code), only processing incoming HCI data. + mp_bluetooth_nimble_hci_uart_process(false); +} + +#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE diff --git a/ports/rp2/mpnimbleport.h b/ports/rp2/mpnimbleport.h new file mode 100644 index 000000000..64debea33 --- /dev/null +++ b/ports/rp2/mpnimbleport.h @@ -0,0 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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_RP2_MPNIMBLEPORT_H +#define MICROPY_INCLUDED_RP2_MPNIMBLEPORT_H + +#endif // MICROPY_INCLUDED_RP2_MPNIMBLEPORT_H diff --git a/ports/rp2/rp2_pio.c b/ports/rp2/rp2_pio.c index 414fa8bd7..fe09ebe24 100644 --- a/ports/rp2/rp2_pio.c +++ b/ports/rp2/rp2_pio.c @@ -613,7 +613,12 @@ STATIC mp_obj_t rp2_state_machine_exec(mp_obj_t self_in, mp_obj_t instr_in) { mp_obj_t rp2_module = mp_import_name(MP_QSTR_rp2, mp_const_none, MP_OBJ_NEW_SMALL_INT(0)); mp_obj_t asm_pio_encode = mp_load_attr(rp2_module, MP_QSTR_asm_pio_encode); uint32_t sideset_count = self->pio->sm[self->sm].pinctrl >> PIO_SM0_PINCTRL_SIDESET_COUNT_LSB; - mp_obj_t encoded_obj = mp_call_function_2(asm_pio_encode, instr_in, MP_OBJ_NEW_SMALL_INT(sideset_count)); + uint8_t sideset_opt = !!(self->pio->sm[self->sm].execctrl & (1 << PIO_SM0_EXECCTRL_SIDE_EN_LSB)); + mp_obj_t args[3]; + args[0] = instr_in; + args[1] = MP_OBJ_NEW_SMALL_INT(sideset_count); + args[2] = MP_OBJ_NEW_SMALL_INT(sideset_opt); + mp_obj_t encoded_obj = mp_call_function_n_kw(asm_pio_encode, 3, 0, args); mp_int_t encoded = mp_obj_get_int(encoded_obj); pio_sm_exec(self->pio, self->sm, encoded); return mp_const_none; diff --git a/ports/samd/Makefile b/ports/samd/Makefile index a84fc3b12..8476eea4b 100644 --- a/ports/samd/Makefile +++ b/ports/samd/Makefile @@ -16,6 +16,10 @@ include $(BOARD_DIR)/mpconfigboard.mk QSTR_DEFS = qstrdefsport.h QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h +MCU_SERIES_LOWER = $(shell echo $(MCU_SERIES) | tr '[:upper:]' '[:lower:]') + +FROZEN_MANIFEST ?= boards/manifest.py + # Include py core make definitions include $(TOP)/py/py.mk @@ -26,14 +30,25 @@ 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/asf4/$(MCU_SERIES_LOWER)/hal/include +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hal/utils/include +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/config +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hri +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/core +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/gclk +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/pm +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/port +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/rtc +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/hpl/tc +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/include +INC += -I$(TOP)/lib/asf4/$(MCU_SERIES_LOWER)/include/pio 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)__ -CFLAGS += $(CFLAGS_MOD) +CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA) LDFLAGS = -nostdlib $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref LDFLAGS += $(LDFLAGS_MOD) @@ -59,12 +74,22 @@ endif SRC_C = \ main.c \ + help.c \ + moduos.c \ modutime.c \ modmachine.c \ + $(BOARD_DIR)/pins.c \ + machine_pin.c \ + machine_led.c \ + modsamd.c \ + samd_flash.c \ mphalport.c \ samd_isr.c \ samd_soc.c \ tusb_port.c \ + lib/asf4/$(MCU_SERIES_LOWER)/hal/src/hal_atomic.c \ + lib/asf4/$(MCU_SERIES_LOWER)/hal/src/hal_flash.c \ + lib/asf4/$(MCU_SERIES_LOWER)/hpl/nvmctrl/hpl_nvmctrl.c \ lib/libm/ef_sqrt.c \ lib/libm/fmodf.c \ lib/libm/math.c \ @@ -81,6 +106,8 @@ SRC_C = \ shared/runtime/gchelper_native.c \ shared/runtime/pyexec.c \ shared/runtime/stdout_helpers.c \ + shared/runtime/sys_stdio_mphal.c \ + shared/timeutils/timeutils.c \ SRC_C += $(SRC_MOD) @@ -93,12 +120,27 @@ SRC_S = shared/runtime/gchelper_m3.s endif # List of sources for qstr extraction -SRC_QSTR += modutime.c modmachine.c $(SRC_MOD) $(SRC_CXX) +SRC_QSTR += moduos.c \ + modutime.c \ + modmachine.c \ + machine_pin.c \ + machine_led.c \ + modsamd.c \ + samd_flash.c \ + +SRC_QSTR += $(SRC_MOD) $(SRC_CXX) OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) + +ifneq ($(FROZEN_MANIFEST),) +CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +CFLAGS += -DMICROPY_MODULE_FROZEN_STR +CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool +endif # 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 diff --git a/ports/samd/README.md b/ports/samd/README.md index b2ff4023e..4b434963d 100644 --- a/ports/samd/README.md +++ b/ports/samd/README.md @@ -3,5 +3,144 @@ Port of MicroPython to Microchip SAMD MCUs Supports SAMD21 and SAMD51. -Features: +## Features: + +### REPL + - REPL over USB VCP +- REPL over USART using board specified USART pins (initialised on startup). + - The USART Pins are board specific, defined in `boards/$(BOARD)/mpconfigboard.h`, + and set at compile time. See the table below. At this stage, the USART cannot be + moved to different pins unless `mpconfigboard.h` is edited and the port recompiled. + - Two USART functions are accessible through MicroPython: + - `uart_init()`. The 'C' function behind this function is what initialises the + USART on startup. Calling this function in MicroPython resets any other peripheral + operating on these pins and reconnects the USART SERCOM to the designated pins. + - `uart_deinit()`. This simply 'disconnects' the SERCOM from the pins. The USART + remains operating over USB VCP to maintain access to the REPL. + +### Boards + +| Board | USART | LFS1 Flash size | Tested | +| ------------------------------------------------------------ | ----------------------------------------------------------- | --------------- | ------ | +| ADAFRUIT_FEATHER_M0_EXPRESS | Tx=PA10=SERCOM0/PAD[2], Rx=PA11=SERCOM0/PAD[3] | 64k | No | +| ADAFRUIT_ITSYBITSY_M4_EXPRESS | Tx=TX_D1=PA17=SERCOM3/PAD[0], Rx=RX_D0=PA16=SERCOM3/PAD[1] | 128k | No | +| ADAFRUIT_TRINKET_M0 | Tx=D4=PA06=SERCOM0/PAD[2], Rx=D3=PA07=SERCOM0/PAD[3] | 64k | No | +| MINISAM_M4 | Tx=TX_D1=PA17=SERCOM3/PAD[0], Rx=RX_D0=PA16=SERCOM3/PAD[1] | 128k | No | +| SAMD21_XPLAINED_PRO | Tx=PA10=SERCOM0/PAD[2], Rx=PA11=SERCOM0/PAD[3] | 64k | No | +| SEEED_WIO_TERMINAL | Tx=BCM14=PB27=SERCOM2/PAD[0], Rx=BCM15=PB26=SERCOM2/PAD[1] | 128k | Yes | +| SEEED_XIAO | Tx=A6=PB8=SERCOM4/PAD[0], Rx=A7=PB9=SERCOM4/PAD[1] | 64k | Yes | + +Note: all USARTs are set to: async, 8 bit, 1 stop bit, no parity, 115200 bps. + +### Modules + +- Internal modules and functions: + +`>>>help('modules')` +`__main__ micropython uheapq ustruct` +`_boot samd uio usys` +`_uasyncio uarray ujson utime` +`builtins uasyncio uos uzlib` +`gc ubinascii urandom` +`machine uctypes ure` +`Plus any modules on the filesystem` + +#### Flash + +- Internal Flash Block Device `samd.Flash()` initialised with littlefs1 in frozen module '`_boot.py`'. + +- **No external SPI Flash driver** (ToDo). + +- Block Device size is set in `ports/samd/boards/$(BOARD)/mpconfigboard.h` : + + - SAMD21: (eg; SEEED_XIAO): 64k `0xFFFF` + + * SAMD51: (eg; M4's): 128k `0x1FFFF` + +#### Pins & LEDs + +##### `machine.Pin()` class. + +- GPIO methods & constants: + + value IN OUT PULL_DOWN + PULL_UP high init low + off on toggle + +- Each board has its own pin numbering scheme, so please see the table below (the + structure is defined in`boards/$(BOARD)/pins.c`) for pin numbers referenced + (index) by 'Pin'. Eg; `SEEED_XIAO/pins.c`: `{{&machine_pin_type}, PIN_PA02}, // A0/D0` + means MicroPython `Pin(0)` is SEEED_XIAO pin "A0/D0" on SAMD21G18A PortA, Pin2. + +- Note: on the SEEED_XIAO, if the TX & TX pins are used by the `Pin()` class, the `Pin()` + initialisation disconnects the pins from the SERCOM similar to the way + `machine.uart_deinit()` does. + +| MicroPython Pin() | SAMD51 Pin#/ ItsyBitsy_M4 | SAMD21 Pin#/ Feather_M0 | SAMD21 Pin#/ Xplained Pro | SAMD21 Pin#/ Trinket_M0 | SAMD51 Pin#/ Minisam | SAMD21 Pin#/ SEEED_XIAO | SAMD51 Pin#/ SEEED_WIO_TERMINAL | +| ----------------- | -------------------------- | ------------------------ | ----------------------------------- | ------------------------ | -------------------- | ----------------------- | ------------------------------------- | +| Pin(0) | PA16/ RX_D0 | PA11/ D0 | PB00/ PIN3_ADC(+) (ext1) | PA08/ D0 | PA02/ A0,D9 | PA02 / A0/D0 | PB08 / A0/D0 | +| Pin(1) | PA17/ TX_D1 | PA10/ D1 | PB01/ PIN4_ADC(-) (ext1) | PA02/ D1 | PB08/ A1,D10 | PA04 / A1/D1 | PB09 / A1/D1 | +| Pin(2) | PA07/ D2 | PA14/ D2 | PB06/ PIN5_GPIO (ext1) | PA09/ D2 | PB09/ A2,D11 | PA10 / A2/D2 | PA07 / A2/D2 | +| Pin(3) | PB22/ D3 | PA09/ D3/ | PB07/ PIN6_GPIO (ext1) | PA07/ D3/ RxD | PA04/ A3,D12 | PA11 / A3/D3 | PB04 / A3/D3 | +| Pin(4) | PA14/ D4 | PA08/ D4/ | PB02/ PIN7_PWM(+) (ext1) | PA06/ D4/ TxD | PA05/ A4,D13 | PA08 / A4/D4 | PB05 / A4/D4 | +| Pin(5) | PA15/ D5 | PA15/ D5 | PB03/ PIN8_PWM(-) (ext1) | | PA06/ A5 | PA09 / A5/D5 | PB06 / A5/D5 | +| Pin(6) | -1/ D6 | PA20/ D6 | PB04/ PIN9_IRQ/GPIO (ext1) | | PA16/ RX_D0 | PB08 / A6/D6/TX | PA04 / A6/D6 | +| Pin(7) | PA18/ D7 | PA21/ D7 | PB05/ PIN10_SPI_SS_B/GPIO (ext1) | | PA17/ TX_D1 | PB09 / A7/D7/RX | PB07 / A7/D7 | +| Pin(8) | -1/ D8 | PA06/ D8/ | PA08/ PIN11_TWI_SDA (ext1) | | PA07/ D2,A6 | PA07 / A8/D8 | PA06 / A8/D8 | +| Pin(9) | PA19/ D9 | PA07/ D9/ | PA09/ PIN12_TWI_SCL (ext1) | | PA19/ D3 | PA05 / A9/D9 | PD08 / SWITCH_X | +| Pin(10) | PA20/ D10 | PA18/ D10 | PB09/ PIN13_UART_RX (ext1) | | PA20/ D4 | PA06 / A10/D10 | PD09 / SWITCH_Y | +| Pin(11) | PA21/ D11 | PA16/ D11 | PB08/ PIN14_UART_TX (ext1) | | PA21/ D5 | | PD10 / SWITCH_Z | +| Pin(12) | PA23/ D12 | PA19/ D12 | PA05/ PIN15_SPI_SS_A (ext1) | | PA00/ BUTTON | | PD12 / SWITCH_B | +| Pin(13) | PA22/ D13 | PA17/ D13/ | PA06/ PIN16_SPI_MOSI (ext1) | | | | PD20 / SWITCH_U | +| Pin(14) | PA02/ A0 | PA02/ A0 | PA04/ PIN17_SPI_MISO (ext1) | | | | PC26 / BUTTON_1 | +| Pin(15) | PA05/ A1 | PB08/ A1 | PA07/ PIN18_SPI_SCK (ext1) | | | | PC27 / BUTTON_2 | +| Pin(16) | PB08/ A2 | PB09/ A2 | PA10/ PIN3_ADC(+) (ext2) | | | | PC28 / BUTTON_3 | +| Pin(17) | PB09/ A3 | PA04/ A3/ | PA11/ PIN4_ADC(-) (ext2) | | | | PD11 / BUZZER_CTR | +| Pin(18) | PA04/ A4 | PA05/ A4/ | PA20/ PIN5_GPIO (ext2) | | | | PC14/ 5V_OUTPUT_CTR- '1'= 5V on hdr | +| Pin(19) | PA06/ A5 | PB02/ A5 | PA21/ PIN6_GPIO (ext2) | | | | PC15/ 3V3_OUTPUT_CTR- '0'= 3V3 on hdr | +| Pin(20) | | | PB12/ PIN7_PWM(+) (ext2) | | | | | +| Pin(21) | | | PB13/ PIN8_PWM(-) (ext2) | | | | | +| Pin(22) | | | PB14/ PIN9_IRQ/GPIO (ext2) | | | | | +| Pin(23) | | | PB15/ PIN10_SPI_SS_B/GPIO (ext2) | | | | | +| Pin(24) | | | -1 / PIN11_TWI_SDA already defined | | | | | +| Pin(25) | | | -1 / PIN12_TWI_SCL already defined | | | | | +| Pin(26) | | | PB11/ PIN13_UART_RX (ext2) | | | | | +| Pin(27) | | | PB10/ PIN14_UART_TX (ext2) | | | | | +| Pin(28) | | | PA17/ PIN15_SPI_SS_A (ext2) | | | | | +| Pin(29) | | | PA18/ PIN16_SPI_MOSI (ext2) | | | | | +| Pin(30) | | | PA16/ PIN17_SPI_MISO (ext2) | | | | | +| Pin(31) | | | PA19/ PIN18_SPI_SCK (ext2) | | | | | +| Pin(32) | | | PA02/ PIN3_ADC(+) (ext3) | | | | | +| Pin(33) | | | PA03/ PIN4_ADC(-) (ext3) | | | | | +| Pin(34) | | | -1/ PIN5_GPIO already defined | | | | | +| Pin(35) | | | PA15/ PIN6_GPIO; USER_BUTTON (ext3) | | | | | +| Pin(36) | | | PA12/ PIN7_PWM(+) (ext3) | | | | | +| Pin(37) | | | PA13/ PIN8_PWM(-) (ext3) | | | | | +| Pin(38) | | | PA28/ PIN9_IRQ/GPIO (ext3) | | | | | +| Pin(39) | | | PA27/ PIN10_SPI_SS_B/GPIO (ext3) | | | | | +| Pin(40) | | | -1/ PIN11_TWI_SDA already defined | | | | | +| Pin(41) | | | -1/ PIN12_TWI_SCL already defined | | | | | +| Pin(42) | | | -1/ PIN13_UART_RX already defined | | | | | +| Pin(43) | | | -1/ PIN14_UART_TX already defined | | | | | +| Pin(44) | | | PA15/ PIN6_GPIO; USER_BUTTON (ext3) | | | | | +| Pin(45) | | | PB22/ PIN16_SPI_MOSI (ext3) | | | | | +| Pin(46) | | | PB16/ PIN17_SPI_MISO (ext3) | | | | | +| Pin(47) | | | PB23/ PIN18_SPI_SCK (ext3) | | | | | + +##### `machine.LED()` class. + +- GPIO methods & constants: + +`value OUT high low` +`off on toggle` + +- As above, please see `boards/$(BOARD)/pins.c` for pin numbers referenced by 'LED'. +Eg; `SEEED_XIAO/pins.c`: `{{&machine_led_type}, PIN_PA17}, // W13` means MicroPython +`LED(0)` is SEEED_XIAO LED "W13" connected to SAMD21G18A PortA, Pin17. + +| MicroPython LED() | SAMD51 Pin#/ ItsyBitsy_M4 | SAMD21 Pin#/ Feather_M0 | SAMD21 Pin#/ Xplained Pro | SAMD21 Pin#/ Trinket_M0 | SAMD51 Pin#/ Minisam | SAMD21 Pin#/ SEEED_XIAO | SAMD51 Pin#/ SEEED_WIO_TERMINAL | +| ------------------ | -------------------------- | ------------------------ | -------------------------- | ------------------------ | --------------------- | ------------------------ | -------------------------------- | +| LED(0) | PA22/ D13/ user LED | PA17/ D13/ user LED | PB30/ USER_LED | PA10/ USER_LED | PA15/ LED | PA17 / W13 | PA15 / USER_LED (Blue) | +| LED(1) | | | | | | PA18 / RX_LED | PC05 / LCD_BACKLIGHT_CTR | +| LED(2) | | | | | | PA19 / TX_LED | | diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json new file mode 100644 index 000000000..b0cb02cd4 --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Battery Charging", + "Breadboard Friendly", + "Feather", + "Micro USB", + "RGB LED", + "SPI Flash" + ], + "images": [ + "feather_m0_express.jpg" + ], + "mcu": "samd21", + "product": "Feather M0 Express", + "thumbnail": "", + "url": "https://www.adafruit.com/product/3403", + "vendor": "Adafruit" +} diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h index cec9e9ccd..ba384645d 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.h @@ -1,2 +1,28 @@ #define MICROPY_HW_BOARD_NAME "Feather M0 Express" #define MICROPY_HW_MCU_NAME "SAMD21G18A" + +// MicroPython configs +// samd_flash.c flash parameters +// Build a 64k Flash storage at top. 256k-64k=196k +// 256*1024=262144 minus 64*1024=65536 = 196608 = 0x30000 +#define MICROPY_HW_FLASH_STORAGE_BASE (0x30000) +#define MICROPY_HW_FLASH_STORAGE_BYTES (0xFFFF) +#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages; + +// ASF4 MCU package specific Pin definitions +#include "samd21g18a.h" + +// Please consult the SAM_D21 Datasheet, I/O Multiplexing and Considerations. +// On this board (see https://learn.adafruit.com/assets/40553) TX is D1 (PA10) and RX is D0 (PA11) +// USART pin assignments: Tx=PA10=SERCOM0/PAD[2], Rx=PA11==SERCOM0/PAD[3] +#define CPU_FREQ (48000000) // For selecting Baud from clock. +#define MP_PIN_GRP 0 // A=0, B=1 +#define MP_TX_PIN 10 //'n' +#define MP_RX_PIN 11 +#define MP_PERIPHERAL_MUX 5 // 'n'th group of 2 pins +#define USARTx SERCOM0 // SERCOM0: tx/rx +#define MP_PORT_FUNC 0x22 // Sets PMUXE & PMUXO to the Alternative Function.(A-H=0-7) +#define MP_RXPO_PAD 3 // RXPO- Receive Data Pinout +#define MP_TXPO_PAD 1 // TXPO- Transmit Data Pinout +#define MP_SERCOMx SERCOM0_ // APBCMASK +#define MP_SERCOM_GCLK_ID_x_CORE GCLK_CLKCTRL_ID_SERCOM0_CORE // Generic Clock Control diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk index 8696c966b..a760cf047 100644 --- a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/mpconfigboard.mk @@ -2,3 +2,7 @@ MCU_SERIES = SAMD21 CMSIS_MCU = SAMD21G18A LD_FILES = boards/samd21x18a.ld sections.ld TEXT0 = 0x2000 + +# The ?='s allow overriding in mpconfigboard.mk. +# MicroPython settings +MICROPY_VFS_LFS1 ?= 1 diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.c b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.c new file mode 100644 index 000000000..e0dd752ec --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.c @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c. Holds Board/MCU specific Pin allocations. + */ + +#include "modmachine.h" +#include "pins.h" + +// Ensure Declaration in 'pins.h' reflects # of Pins defined here. +const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, PIN_PA11}, // D0 + {{&machine_pin_type}, PIN_PA10}, // D1 + {{&machine_pin_type}, PIN_PA14}, // D2 + {{&machine_pin_type}, PIN_PA09}, // D3/ + {{&machine_pin_type}, PIN_PA08}, // D4/ + {{&machine_pin_type}, PIN_PA15}, // D5 + {{&machine_pin_type}, PIN_PA20}, // D6 + {{&machine_pin_type}, PIN_PA21}, // D7 + {{&machine_pin_type}, PIN_PA06}, // D8/ + {{&machine_pin_type}, PIN_PA07}, // D9/ + {{&machine_pin_type}, PIN_PA18}, // D10 + {{&machine_pin_type}, PIN_PA16}, // D11 + {{&machine_pin_type}, PIN_PA19}, // D12 + {{&machine_pin_type}, PIN_PA17}, // D13/ + {{&machine_pin_type}, PIN_PA02}, // A0 + {{&machine_pin_type}, PIN_PB08}, // A1 + {{&machine_pin_type}, PIN_PB09}, // A2 + {{&machine_pin_type}, PIN_PA04}, // A3/ + {{&machine_pin_type}, PIN_PA05}, // A4/ + {{&machine_pin_type}, PIN_PB02}, // A5 +}; + +const machine_led_obj_t machine_led_obj[] = { + {{&machine_led_type}, PIN_PA17}, // D13/ user LED +}; diff --git a/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.h b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.h new file mode 100644 index 000000000..45bee6167 --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_FEATHER_M0_EXPRESS/pins.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin + * allocations. + */ + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_pin_obj_t; + +typedef struct _machine_led_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_led_obj_t; + +// MUST explicitly hold array # of rows, else machine_pin.c wont compile. +extern const machine_pin_obj_t machine_pin_obj[20]; +extern const machine_led_obj_t machine_led_obj[1]; diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json new file mode 100644 index 000000000..83db285b4 --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.json @@ -0,0 +1,20 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly", + "Micro USB", + "RGB LED", + "SPI Flash" + ], + "images": [ + "itsybitsy_m4_express.jpg" + ], + "mcu": "samd51", + "product": "ItsyBitsy M4 Express", + "thumbnail": "", + "url": "https://www.adafruit.com/product/3800", + "vendor": "Adafruit" +} diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h index 490704ead..c1c4fd8ca 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h @@ -5,3 +5,28 @@ #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_PY_MATH (0) #define MICROPY_PY_CMATH (0) + +// MicroPython configs +// samd_flash.c flash parameters +// Build a 128k Flash storage at top. 512k-128k=384k=0x60000 +// 512*1024= 0x80000 minus 128*1024= 0x20000 = 0x60000 +#define MICROPY_HW_FLASH_STORAGE_BASE (0x60000) +#define MICROPY_HW_FLASH_STORAGE_BYTES (0x1FFFF) +#define VFS_BLOCK_SIZE_BYTES (1536) // + +// ASF4 MCU package specific Pin definitions +#include "samd51g19a.h" + +// Please consult the SAM_D51 Datasheet, I/O Multiplexing and Considerations. +// USART pin assignments: Tx=TX_D1=PA17=SERCOM3/PAD[0], Rx=RX_D0=PA16=SERCOM3/PAD[1] +#define CPU_FREQ (48000000) // For selecting Baud from clock. +#define MP_PIN_GRP 1 // A-D=0-3 +#define MP_TX_PIN 17 +#define MP_RX_PIN 16 // 'n' +#define MP_PERIPHERAL_MUX 8 // 'n'th group of 2 pins +#define USARTx SERCOM3 // +#define MP_PORT_FUNC 0x33 // Sets PMUXE & PMUXO to the Alternative Function.A-N=0-13 +#define MP_RXPO_PAD 1 // RXPO- Receive Data Pinout +#define MP_TXPO_PAD 0 // TXPO- Tranmit Data Pinout +#define MP_SERCOMx SERCOM3_ // APBCMASK +#define MP_SERCOM_GCLK_ID_x_CORE SERCOM3_GCLK_ID_CORE diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk index 2e5d7e68d..6b0192c77 100644 --- a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.mk @@ -2,3 +2,7 @@ MCU_SERIES = SAMD51 CMSIS_MCU = SAMD51G19A LD_FILES = boards/samd51g19a.ld sections.ld TEXT0 = 0x4000 + +# The ?='s allow overriding in mpconfigboard.mk. +# MicroPython settings +MICROPY_VFS_LFS1 ?= 1 diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.c b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.c new file mode 100644 index 000000000..82948ccbc --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.c @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c. Holds Board/MCU specific Pin allocations. + */ + +#include "modmachine.h" +#include "pins.h" + +// Ensure Declaration in 'pins.h' reflects # of Pins defined here. +const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, PIN_PA16}, // RX_D0 + {{&machine_pin_type}, PIN_PA17}, // TX_D1 + {{&machine_pin_type}, PIN_PA07}, // D2 + {{&machine_pin_type}, PIN_PB22}, // D3 + {{&machine_pin_type}, PIN_PA14}, // D4 + {{&machine_pin_type}, PIN_PA15}, // D5 + {{NULL}, -1}, // D6- not terminated on breakout. + {{&machine_pin_type}, PIN_PA18}, // D7 + {{NULL}, -1}, // D8- not terminated on breakout. + {{&machine_pin_type}, PIN_PA19}, // D9 + {{&machine_pin_type}, PIN_PA20}, // D10 + {{&machine_pin_type}, PIN_PA21}, // D11 + {{&machine_pin_type}, PIN_PA23}, // D12 + {{&machine_pin_type}, PIN_PA22}, // D13 + {{&machine_pin_type}, PIN_PA02}, // A0 + {{&machine_pin_type}, PIN_PA05}, // A1 + {{&machine_pin_type}, PIN_PB08}, // A2 + {{&machine_pin_type}, PIN_PB09}, // A3 + {{&machine_pin_type}, PIN_PA04}, // A4 + {{&machine_pin_type}, PIN_PA06}, // A5 +}; + +const machine_led_obj_t machine_led_obj[] = { + {{&machine_led_type}, PIN_PA22}, // D13 +}; diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.h b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.h new file mode 100644 index 000000000..45bee6167 --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/pins.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin + * allocations. + */ + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_pin_obj_t; + +typedef struct _machine_led_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_led_obj_t; + +// MUST explicitly hold array # of rows, else machine_pin.c wont compile. +extern const machine_pin_obj_t machine_pin_obj[20]; +extern const machine_led_obj_t machine_led_obj[1]; diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json new file mode 100644 index 000000000..9112bc06e --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Breadboard Friendly", + "Micro USB", + "RGB LED" + ], + "images": [ + "trinket_m0.jpg" + ], + "mcu": "samd21", + "product": "Trinket M0", + "thumbnail": "", + "url": "https://www.adafruit.com/product/3500", + "vendor": "Adafruit" +} diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h index d3a6ba2d8..128689f4f 100644 --- a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h @@ -1,2 +1,27 @@ #define MICROPY_HW_BOARD_NAME "Trinket M0" #define MICROPY_HW_MCU_NAME "SAMD21E18A" + +// MicroPython configs +// samd_flash.c flash parameters +// Build a 64k Flash storage at top. 256k-64k=196k +// 256*1024=262144 minus 64*1024=65536 = 196608 = 0x30000 +#define MICROPY_HW_FLASH_STORAGE_BASE (0x30000) +#define MICROPY_HW_FLASH_STORAGE_BYTES (0xFFFF) +#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages; + +// ASF4 MCU package specific Pin definitions +#include "samd21e18a.h" + +// Please consult the SAM_D21 Datasheet, I/O Multiplexing and Considerations. +// USART pin assignments: Tx=D4=PA06=SERCOM0/PAD[2], Rx=D3=PA07=SERCOM0/PAD[3] +#define CPU_FREQ (48000000) // For selecting Baud from clock. +#define MP_PIN_GRP 1 // A=0, B=1 +#define MP_TX_PIN 6 // 'n' +#define MP_RX_PIN 7 +#define MP_PERIPHERAL_MUX 3 // 'n'th group of 2 pins +#define USARTx SERCOM0 // SERCOM0: tx/rx +#define MP_PORT_FUNC 0x33 // Sets PMUXE & PMUXO to the Alternative Function.A-H=0-7 +#define MP_RXPO_PAD 3 // RXPO- Receive Data Pinout +#define MP_TXPO_PAD 2 // TXPO- Tranmit Data Pinout +#define MP_SERCOMx SERCOM0_ // APBCMASK +#define MP_SERCOM_GCLK_ID_x_CORE GCLK_CLKCTRL_ID_SERCOM0_CORE // Generic Clock Control diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk index 5b4d0b63e..448da296f 100644 --- a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.mk @@ -2,3 +2,7 @@ MCU_SERIES = SAMD21 CMSIS_MCU = SAMD21E18A LD_FILES = boards/samd21x18a.ld sections.ld TEXT0 = 0x2000 + +# The ?='s allow overriding in mpconfigboard.mk. +# MicroPython settings +MICROPY_VFS_LFS1 ?= 1 diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.c b/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.c new file mode 100644 index 000000000..9fecddb6c --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.c @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c. Holds Board/MCU specific Pin allocations. + */ + +#include "modmachine.h" +#include "pins.h" + +// Ensure Declaration in 'pins.h' reflects # of Pins defined here. +const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, PIN_PA08}, // D0 + {{&machine_pin_type}, PIN_PA02}, // D1 + {{&machine_pin_type}, PIN_PA09}, // D2 + {{&machine_pin_type}, PIN_PA07}, // D3/ RxD + {{&machine_pin_type}, PIN_PA06}, // D4/ TxD +}; + +const machine_led_obj_t machine_led_obj[] = { + {{&machine_led_type}, PIN_PA10}, // user LED +}; diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.h b/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.h new file mode 100644 index 000000000..843d69add --- /dev/null +++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/pins.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin + * allocations. + */ + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_pin_obj_t; + +typedef struct _machine_led_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_led_obj_t; + +// MUST explicitly hold array # of rows, else machine_pin.c wont compile. +extern const machine_pin_obj_t machine_pin_obj[5]; +extern const machine_led_obj_t machine_led_obj[1]; diff --git a/ports/samd/boards/MINISAM_M4/board.json b/ports/samd/boards/MINISAM_M4/board.json new file mode 100644 index 000000000..126e03640 --- /dev/null +++ b/ports/samd/boards/MINISAM_M4/board.json @@ -0,0 +1,19 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Micro USB", + "RGB LED", + "SPI Flash" + ], + "images": [ + "mini_sam_m4.jpg" + ], + "mcu": "samd51", + "product": "Mini SAM M4", + "thumbnail": "", + "url": "https://minifigboards.com/products/mini-sam-m4", + "vendor": "MiniFig Boards" +} diff --git a/ports/samd/boards/MINISAM_M4/mpconfigboard.h b/ports/samd/boards/MINISAM_M4/mpconfigboard.h index 0847a45bf..a65eb54b4 100644 --- a/ports/samd/boards/MINISAM_M4/mpconfigboard.h +++ b/ports/samd/boards/MINISAM_M4/mpconfigboard.h @@ -5,3 +5,28 @@ #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_PY_MATH (0) #define MICROPY_PY_CMATH (0) + +// MicroPython configs +// samd_flash.c flash parameters +// Build a 128k Flash storage at top. 512k-128k=384k=0x60000 +// 512*1024= 0x80000 minus 128*1024= 0x20000 = 0x60000 +#define MICROPY_HW_FLASH_STORAGE_BASE (0x60000) +#define MICROPY_HW_FLASH_STORAGE_BYTES (0x1FFFF) +#define VFS_BLOCK_SIZE_BYTES (1536) // + +// ASF4 MCU package specific Pin definitions +#include "samd51g19a.h" + +// Please consult the SAM_D51 Datasheet, I/O Multiplexing and Considerations. +// USART pin assignments: Tx=TX_D1=PA17=SERCOM3/PAD[0], Rx=RX_D0=PA16=SERCOM3/PAD[1] +#define CPU_FREQ (48000000) // For selecting Baud from clock. +#define MP_PIN_GRP 0 // A-D=0-3 +#define MP_TX_PIN 17 +#define MP_RX_PIN 16 // 'n' +#define MP_PERIPHERAL_MUX 8 // 'n'th group of 2 pins +#define USARTx SERCOM3 // +#define MP_PORT_FUNC 0x33 // Sets PMUXE & PMUXO to the Alternative Function.A-N=0-13 +#define MP_RXPO_PAD 1 // RXPO- Receive Data Pinout +#define MP_TXPO_PAD 0 // TXPO- Tranmit Data Pinout +#define MP_SERCOMx SERCOM3_ // APBCMASK +#define MP_SERCOM_GCLK_ID_x_CORE SERCOM3_GCLK_ID_CORE diff --git a/ports/samd/boards/MINISAM_M4/mpconfigboard.mk b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk index 54ed3273d..6ed0ff552 100644 --- a/ports/samd/boards/MINISAM_M4/mpconfigboard.mk +++ b/ports/samd/boards/MINISAM_M4/mpconfigboard.mk @@ -3,3 +3,7 @@ MCU_SERIES = SAMD51 CMSIS_MCU = SAMD51G19A LD_FILES = boards/samd51g19a.ld sections.ld TEXT0 = 0x4000 + +# The ?='s allow overriding in mpconfigboard.mk. +# MicroPython settings +MICROPY_VFS_LFS1 ?= 1 diff --git a/ports/samd/boards/MINISAM_M4/pins.c b/ports/samd/boards/MINISAM_M4/pins.c new file mode 100644 index 000000000..6cdd840b6 --- /dev/null +++ b/ports/samd/boards/MINISAM_M4/pins.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c. Holds Board/MCU specific Pin allocations. + */ + +#include "modmachine.h" +#include "pins.h" + +// Ensure Declaration in 'pins.h' reflects # of Pins defined here. +const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, PIN_PA02}, // A0,D9 + {{&machine_pin_type}, PIN_PB08}, // A1,D10 + {{&machine_pin_type}, PIN_PB09}, // A2,D11 + {{&machine_pin_type}, PIN_PA04}, // A3,D12 + {{&machine_pin_type}, PIN_PA05}, // A4,D13 + {{&machine_pin_type}, PIN_PA06}, // A5 + {{&machine_pin_type}, PIN_PA16}, // RX_D0 + {{&machine_pin_type}, PIN_PA17}, // TX_D1 + {{&machine_pin_type}, PIN_PA07}, // D2,A6 + {{&machine_pin_type}, PIN_PA19}, // D3 + {{&machine_pin_type}, PIN_PA20}, // D4 + {{&machine_pin_type}, PIN_PA21}, // D5 + {{&machine_pin_type}, PIN_PA00}, // BUTTON +}; + +const machine_led_obj_t machine_led_obj[] = { + {{&machine_led_type}, PIN_PA15}, // LED +}; diff --git a/ports/samd/boards/MINISAM_M4/pins.h b/ports/samd/boards/MINISAM_M4/pins.h new file mode 100644 index 000000000..892b0e7b9 --- /dev/null +++ b/ports/samd/boards/MINISAM_M4/pins.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin + * allocations. + */ + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_pin_obj_t; + +typedef struct _machine_led_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_led_obj_t; + +// MUST explicitly hold array # of rows, else machine_pin.c wont compile. +extern const machine_pin_obj_t machine_pin_obj[13]; +extern const machine_led_obj_t machine_led_obj[1]; diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json b/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json new file mode 100644 index 000000000..4d22c42ba --- /dev/null +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/board.json @@ -0,0 +1,16 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "Micro USB", + "SPI Flash" + ], + "images": ["2033-atsamd21-xpro.jpg"], + "mcu": "samd21", + "product": "SAMD21 Xplained Pro", + "thumbnail": "", + "url": "https://www.microchip.com/en-us/development-tool/atsamd21-xpro", + "vendor": "Microchip" +} diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h index c69b5b4c1..a7dbf7614 100644 --- a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.h @@ -1,2 +1,28 @@ #define MICROPY_HW_BOARD_NAME "SAMD21-XPLAINED-PRO" #define MICROPY_HW_MCU_NAME "SAMD21J18A" + +// MicroPython configs +// samd_flash.c flash parameters +// Build a 64k Flash storage at top. 256k-64k=196k +// 256*1024=262144 minus 64*1024=65536 = 196608 = 0x30000 +#define MICROPY_HW_FLASH_STORAGE_BASE (0x30000) +#define MICROPY_HW_FLASH_STORAGE_BYTES (0xFFFF) +#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages; + +// ASF4 MCU package specific Pin definitions +#include "samd21j18a.h" + +// Please consult the SAM_D21 Datasheet, I/O Multiplexing and Considerations. +// USART pin assignments: (This board has 3 USARTS brought out to the pins. See https://docs.zephyrproject.org/1.14.1/boards/arm/atsamd21_xpro/doc/index.html#serial-port ) +// Tx=PA10=SERCOM0/PAD[2], Rx=PA11=SERCOM0/PAD[3] +#define CPU_FREQ (48000000) // For selecting Baud from clock. +#define MP_PIN_GRP 1 // A=0, B=1 +#define MP_TX_PIN 10 // 'n' +#define MP_RX_PIN 11 +#define MP_PERIPHERAL_MUX 5 // 'n'th group of 2 pins +#define USARTx SERCOM0 // SERCOM0: tx/rx +#define MP_PORT_FUNC 0x22 // Sets PMUXE & PMUXO to the Alternative Function.(A-H=0-7) +#define MP_RXPO_PAD 3 // RXPO- Receive Data Pinout +#define MP_TXPO_PAD 2 // TXPO- Tranmit Data Pinout +#define MP_SERCOMx SERCOM0_ // APBCMASK +#define MP_SERCOM_GCLK_ID_x_CORE GCLK_CLKCTRL_ID_SERCOM0_CORE // Generic Clock Control diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk index f95c65493..b298c9d7f 100644 --- a/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/mpconfigboard.mk @@ -2,3 +2,7 @@ MCU_SERIES = SAMD21 CMSIS_MCU = SAMD21J18A LD_FILES = boards/samd21x18a.ld sections.ld TEXT0 = 0x2000 + +# The ?='s allow overriding in mpconfigboard.mk. +# MicroPython settings +MICROPY_VFS_LFS1 ?= 1 \ No newline at end of file diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.c b/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.c new file mode 100644 index 000000000..2a2d50eb4 --- /dev/null +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.c @@ -0,0 +1,91 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c. Holds Board/MCU specific Pin allocations. + */ + +#include "modmachine.h" +#include "pins.h" + +// Ensure Declaration in 'pins.h' reflects # of Pins defined here. +const machine_pin_obj_t machine_pin_obj[] = { + // EXT1 + {{&machine_pin_type}, PIN_PB00}, // PIN3_ADC(+) + {{&machine_pin_type}, PIN_PB01}, // PIN4_ADC(-) + {{&machine_pin_type}, PIN_PB06}, // PIN5_GPIO + {{&machine_pin_type}, PIN_PB07}, // PIN6_GPIO + {{&machine_pin_type}, PIN_PB02}, // PIN7_PWM(+) + {{&machine_pin_type}, PIN_PB03}, // PIN8_PWM(-) + {{&machine_pin_type}, PIN_PB04}, // PIN9_IRQ/GPIO + {{&machine_pin_type}, PIN_PB05}, // PIN10_SPI_SS_B/GPIO + {{&machine_pin_type}, PIN_PA08}, // PIN11_TWI_SDA + {{&machine_pin_type}, PIN_PA09}, // PIN12_TWI_SCL + {{&machine_pin_type}, PIN_PB09}, // PIN13_UART_RX + {{&machine_pin_type}, PIN_PB08}, // PIN14_UART_TX + {{&machine_pin_type}, PIN_PA05}, // PIN15_SPI_SS_A + {{&machine_pin_type}, PIN_PA06}, // PIN16_SPI_MOSI + {{&machine_pin_type}, PIN_PA04}, // PIN17_SPI_MISO + {{&machine_pin_type}, PIN_PA07}, // PIN18_SPI_SCK + + // EXT2 + {{&machine_pin_type}, PIN_PA10}, // PIN3_ADC(+) + {{&machine_pin_type}, PIN_PA11}, // PIN4_ADC(-) + {{&machine_pin_type}, PIN_PA20}, // PIN5_GPIO + {{&machine_pin_type}, PIN_PA21}, // PIN6_GPIO + {{&machine_pin_type}, PIN_PB12}, // PIN7_PWM(+) + {{&machine_pin_type}, PIN_PB13}, // PIN8_PWM(-) + {{&machine_pin_type}, PIN_PB14}, // PIN9_IRQ/GPIO + {{&machine_pin_type}, PIN_PB15}, // PIN10_SPI_SS_B/GPIO + {{NULL}, -1}, // PIN_PA08/ PIN11_TWI_SDA already defined + {{NULL}, -1}, // PIN_PA09/ PIN12_TWI_SCL already defined + {{&machine_pin_type}, PIN_PB11}, // PIN13_UART_RX + {{&machine_pin_type}, PIN_PB10}, // PIN14_UART_TX + {{&machine_pin_type}, PIN_PA17}, // PIN15_SPI_SS_A + {{&machine_pin_type}, PIN_PA18}, // PIN16_SPI_MOSI + {{&machine_pin_type}, PIN_PA16}, // PIN17_SPI_MISO + {{&machine_pin_type}, PIN_PA19}, // PIN18_SPI_SCK + + // EXT3 + {{&machine_pin_type}, PIN_PA02}, // PIN3_ADC(+) + {{&machine_pin_type}, PIN_PA03}, // PIN4_ADC(-) + {{NULL}, -1}, // PIN_PB30/ PIN5_GPIO already defined + {{&machine_pin_type}, PIN_PA15}, // PIN6_GPIO; USER_BUTTON + {{&machine_pin_type}, PIN_PA12}, // PIN7_PWM(+) + {{&machine_pin_type}, PIN_PA13}, // PIN8_PWM(-) + {{&machine_pin_type}, PIN_PA28}, // PIN9_IRQ/GPIO + {{&machine_pin_type}, PIN_PA27}, // PIN10_SPI_SS_B/GPIO + {{NULL}, -1}, // PIN_PA08/ PIN11_TWI_SDA already defined + {{NULL}, -1}, // PIN_PA09/ PIN12_TWI_SCL already defined + {{NULL}, -1}, // PIN_PB11/ PIN13_UART_RX already defined + {{NULL}, -1}, // PIN_PB10/ PIN14_UART_TX already defined + {{&machine_pin_type}, PIN_PB17}, // PIN15_SPI_SS_A + {{&machine_pin_type}, PIN_PB22}, // PIN16_SPI_MOSI + {{&machine_pin_type}, PIN_PB16}, // PIN17_SPI_MISO + {{&machine_pin_type}, PIN_PB23}, // PIN18_SPI_SCK +}; + +const machine_led_obj_t machine_led_obj[] = { + {{&machine_led_type}, PIN_PB30}, // USER_LED +}; diff --git a/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.h b/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.h new file mode 100644 index 000000000..0b0e878b4 --- /dev/null +++ b/ports/samd/boards/SAMD21_XPLAINED_PRO/pins.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin + * allocations. + */ + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_pin_obj_t; + +typedef struct _machine_led_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_led_obj_t; + +// MUST explicitly hold array # of rows, else machine_pin.c wont compile. +extern const machine_pin_obj_t machine_pin_obj[48]; +extern const machine_led_obj_t machine_led_obj[1]; diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/board.json b/ports/samd/boards/SEEED_WIO_TERMINAL/board.json new file mode 100644 index 000000000..350ada4c4 --- /dev/null +++ b/ports/samd/boards/SEEED_WIO_TERMINAL/board.json @@ -0,0 +1,20 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "USB-C", + "Display", + "Grove", + "WiFi", + "BLE", + "SDCard" + ], + "images": ["wio-terminal.jpg"], + "mcu": "samd51", + "product": "Wio Terminal D51R", + "thumbnail": "", + "url": "https://www.seeedstudio.com/Wio-Terminal-p-4509.html", + "vendor": "Seeed Studio" +} diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.h b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.h new file mode 100644 index 000000000..290bd802b --- /dev/null +++ b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.h @@ -0,0 +1,32 @@ +#define MICROPY_HW_BOARD_NAME "Wio Terminal D51R" +#define MICROPY_HW_MCU_NAME "SAMD51P19A" + +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) + +// MicroPython configs +// samd_flash.c flash parameters +// Build a 128k Flash storage at top. 512k-128k=384k=0x60000 +// 512*1024= 0x80000 minus 128*1024= 0x20000 = 0x60000 +#define MICROPY_HW_FLASH_STORAGE_BASE (0x60000) +#define MICROPY_HW_FLASH_STORAGE_BYTES (0x1FFFF) +#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages; + +// ASF4 MCU package specific Pin definitions +#include "samd51p19a.h" + +// Please consult the SAM_D51 Datasheet, I/O Multiplexing and Considerations. +// WIO_Terminal USART pin assignments: Tx=BCM14=PB27=SERCOM2/PAD[0], Rx=BCM15=PB26=SERCOM2/PAD[1] +#define CPU_FREQ (48000000) // For selecting Baud from clock. +#define MP_PIN_GRP 1 // A-D=0-3 +#define MP_TX_PIN 27 +#define MP_RX_PIN 26 // 'n' +#define MP_PERIPHERAL_MUX 13 // 'n'th group of 2 pins +#define USARTx SERCOM2 // +#define MP_PORT_FUNC 0x22 // Sets PMUXE & PMUXO to the Alternative Function.A-N=0-13 +#define MP_RXPO_PAD 1 // RXPO- Receive Data Pinout +#define MP_TXPO_PAD 0 // TXPO- Tranmit Data Pinout +#define MP_SERCOMx SERCOM2_ // APBCMASK +#define MP_SERCOM_GCLK_ID_x_CORE SERCOM2_GCLK_ID_CORE diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk new file mode 100644 index 000000000..90fb7f2dd --- /dev/null +++ b/ports/samd/boards/SEEED_WIO_TERMINAL/mpconfigboard.mk @@ -0,0 +1,8 @@ +MCU_SERIES = SAMD51 +CMSIS_MCU = SAMD51P19A +LD_FILES = boards/samd51p19a.ld sections.ld +TEXT0 = 0x4000 + +# The ?='s allow overriding in mpconfigboard.mk. +# MicroPython settings +MICROPY_VFS_LFS1 ?= 1 diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/pins.c b/ports/samd/boards/SEEED_WIO_TERMINAL/pins.c new file mode 100644 index 000000000..9862552fa --- /dev/null +++ b/ports/samd/boards/SEEED_WIO_TERMINAL/pins.c @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c. Holds Board/MCU specific Pin allocations. + */ + +#include "modmachine.h" +#include "pins.h" + +// Ensure Declaration in "pins.h" reflects # of Pins defined here. +const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, PIN_PB08}, // A0/D0 + {{&machine_pin_type}, PIN_PB09}, // A1/D1 + {{&machine_pin_type}, PIN_PA07}, // A2/D2 + {{&machine_pin_type}, PIN_PB04}, // A3/D3 + {{&machine_pin_type}, PIN_PB05}, // A4/D4 + {{&machine_pin_type}, PIN_PB06}, // A5/D5 + {{&machine_pin_type}, PIN_PA04}, // A6/D6 + {{&machine_pin_type}, PIN_PB07}, // A7/D7 + {{&machine_pin_type}, PIN_PA06}, // A8/D8 + {{&machine_pin_type}, PIN_PD08}, // SWITCH_X + {{&machine_pin_type}, PIN_PD09}, // SWITCH_Y + {{&machine_pin_type}, PIN_PD10}, // SWITCH_Z + {{&machine_pin_type}, PIN_PD12}, // SWITCH_B + {{&machine_pin_type}, PIN_PD20}, // SWITCH_U + {{&machine_pin_type}, PIN_PC26}, // BUTTON_1 + {{&machine_pin_type}, PIN_PC27}, // BUTTON_2 + {{&machine_pin_type}, PIN_PC28}, // BUTTON_3 + {{&machine_pin_type}, PIN_PD11}, // BUZZER_CTR + {{&machine_pin_type}, PIN_PC14}, // 5V_OUTPUT_CTR- enable 5V on hdr + {{&machine_pin_type}, PIN_PC15}, // 3V3_OUTPUT_CTR- enable 3V3 on hdr +}; + +// Ensure Declaration in 'pins.h' reflects # of Pins defined here. +const machine_led_obj_t machine_led_obj[] = { + {{&machine_led_type}, PIN_PA15}, // USER_LED (Blue) + {{&machine_led_type}, PIN_PC05}, // LCD_BACKLIGHT_CTR +}; diff --git a/ports/samd/boards/SEEED_WIO_TERMINAL/pins.h b/ports/samd/boards/SEEED_WIO_TERMINAL/pins.h new file mode 100644 index 000000000..45ecc254f --- /dev/null +++ b/ports/samd/boards/SEEED_WIO_TERMINAL/pins.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin + * allocations. + */ + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_pin_obj_t; + +typedef struct _machine_led_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_led_obj_t; + +// MUST explicitly hold array # of rows, else machine_pin.c wont compile. +extern const machine_pin_obj_t machine_pin_obj[20]; +extern const machine_led_obj_t machine_led_obj[2]; diff --git a/ports/samd/boards/SEEED_XIAO/board.json b/ports/samd/boards/SEEED_XIAO/board.json new file mode 100644 index 000000000..f5fe27184 --- /dev/null +++ b/ports/samd/boards/SEEED_XIAO/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "USB-C" + ], + "images": ["seeeduino-xiao.jpg"], + "mcu": "samd21", + "product": "Seeeduino XIAO", + "thumbnail": "", + "url": "https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html", + "vendor": "Seeed Studio" +} diff --git a/ports/samd/boards/SEEED_XIAO/mpconfigboard.h b/ports/samd/boards/SEEED_XIAO/mpconfigboard.h new file mode 100644 index 000000000..6422d7ea0 --- /dev/null +++ b/ports/samd/boards/SEEED_XIAO/mpconfigboard.h @@ -0,0 +1,27 @@ +#define MICROPY_HW_BOARD_NAME "Seeed Xiao" +#define MICROPY_HW_MCU_NAME "SAMD21G18A" + +// MicroPython configs +// samd_flash.c flash parameters +// Build a 64k Flash storage at top. 256k-64k=196k +// 256*1024=262144 minus 64*1024=65536 = 196608 = 0x30000 +#define MICROPY_HW_FLASH_STORAGE_BASE (0x30000) +#define MICROPY_HW_FLASH_STORAGE_BYTES (0xFFFF) +#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages; + +// ASF4 MCU package specific Pin definitions +#include "samd21g18a.h" + +// Please consult the SAM_D21 Datasheet, I/O Multiplexing and Considerations. +// XIAO_M0 USART pin assignments: Tx=A6=PB8=SERCOM4/PAD[0], Rx=PB9=A7=SERCOM4/PAD[1] +#define CPU_FREQ (48000000) // For selecting Baud from clock. +#define MP_PIN_GRP 1 // A=0, B=1 +#define MP_TX_PIN 8 // 'n' +#define MP_RX_PIN 9 +#define MP_PERIPHERAL_MUX 4 // 'n'th group of 2 pins +#define USARTx SERCOM4 // SERCOM4:XIAO_M0 tx/rx +#define MP_PORT_FUNC 0x33 // Sets PMUXE & PMUXO to the Alternative Function.A-H=0-7 +#define MP_RXPO_PAD 1 // RXPO- Receive Data Pinout +#define MP_TXPO_PAD 0 // TXPO- Tranmit Data Pinout +#define MP_SERCOMx SERCOM4_ // APBCMASK +#define MP_SERCOM_GCLK_ID_x_CORE GCLK_CLKCTRL_ID_SERCOM4_CORE // Generic Clock Control diff --git a/ports/samd/boards/SEEED_XIAO/mpconfigboard.mk b/ports/samd/boards/SEEED_XIAO/mpconfigboard.mk new file mode 100644 index 000000000..eb4d4d045 --- /dev/null +++ b/ports/samd/boards/SEEED_XIAO/mpconfigboard.mk @@ -0,0 +1,9 @@ +MCU_SERIES = SAMD21 +CMSIS_MCU = SAMD21G18A +LD_FILES = boards/samd21x18a.ld sections.ld +TEXT0 = 0x2000 + +# The ?='s allow overriding in mpconfigboard.mk. +# MicroPython settings +MICROPY_VFS_LFS1 ?= 1 + diff --git a/ports/samd/boards/SEEED_XIAO/pins.c b/ports/samd/boards/SEEED_XIAO/pins.c new file mode 100644 index 000000000..6043913d2 --- /dev/null +++ b/ports/samd/boards/SEEED_XIAO/pins.c @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c. Holds Board/MCU specific Pin allocations. + */ + +#include "modmachine.h" +#include "pins.h" + +// Ensure Declaration in 'pins.h' reflects # of Pins defined here. +const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, PIN_PA02}, // A0/D0 + {{&machine_pin_type}, PIN_PA04}, // A1/D1 + {{&machine_pin_type}, PIN_PA10}, // A2/D2 + {{&machine_pin_type}, PIN_PA11}, // A3/D3 + {{&machine_pin_type}, PIN_PA08}, // A4/D4 + {{&machine_pin_type}, PIN_PA09}, // A5/D5 + {{&machine_pin_type}, PIN_PB08}, // A6/D6 + {{&machine_pin_type}, PIN_PB09}, // A7/D7 + {{&machine_pin_type}, PIN_PA07}, // A8/D8 + {{&machine_pin_type}, PIN_PA05}, // A9/D9 + {{&machine_pin_type}, PIN_PA06}, // A10/D10 +}; + +const machine_led_obj_t machine_led_obj[] = { +// XIAO: Just the available LED Pins: User LED (PA17), Rx & Tx. + {{&machine_led_type}, PIN_PA17}, // W13 + {{&machine_led_type}, PIN_PA18}, // RX_LED + {{&machine_led_type}, PIN_PA19}, // TX_LED +}; diff --git a/ports/samd/boards/SEEED_XIAO/pins.h b/ports/samd/boards/SEEED_XIAO/pins.h new file mode 100644 index 000000000..226b3f1d7 --- /dev/null +++ b/ports/samd/boards/SEEED_XIAO/pins.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Peter van der Burg + * + * 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. + * + * Used by machine_pin.c & board specific pins.c. Holds Board/MCU specific Pin + * allocations. + */ + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_pin_obj_t; + +typedef struct _machine_led_obj_t { + mp_obj_base_t base; + uint32_t id; +} machine_led_obj_t; + +// MUST explicitly hold array # of rows, else machine_pin.c wont compile. +extern const machine_pin_obj_t machine_pin_obj[11]; +extern const machine_led_obj_t machine_led_obj[3]; diff --git a/ports/samd/boards/deploy.md b/ports/samd/boards/deploy.md new file mode 100644 index 000000000..e69de29bb diff --git a/ports/samd/boards/manifest.py b/ports/samd/boards/manifest.py new file mode 100644 index 000000000..c80309cf6 --- /dev/null +++ b/ports/samd/boards/manifest.py @@ -0,0 +1 @@ +freeze("$(PORT_DIR)/modules") diff --git a/ports/samd/boards/samd51p19a.ld b/ports/samd/boards/samd51p19a.ld new file mode 100644 index 000000000..e0baa9bba --- /dev/null +++ b/ports/samd/boards/samd51p19a.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/help.c b/ports/samd/help.c new file mode 100644 index 000000000..577d153b5 --- /dev/null +++ b/ports/samd/help.c @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char samd_help_text[] = + "Welcome to MicroPython!\n" + "\n" + "For online docs please visit http://docs.micropython.org/en/latest/samd/ .\n" + "\n" + "Control commands:\n" + " CTRL-A -- on a blank line, enter raw REPL mode\n" + " CTRL-B -- on a blank line, enter normal REPL mode\n" + " CTRL-C -- interrupt a running program\n" + " CTRL-D -- on a blank line, do a soft reset of the board\n" + " CTRL-E -- on a blank line, enter paste mode\n" + "\n" + "For further help on a specific object, type help('obj')\n" +; diff --git a/ports/samd/machine_led.c b/ports/samd/machine_led.c new file mode 100644 index 000000000..f4dd1aeb3 --- /dev/null +++ b/ports/samd/machine_led.c @@ -0,0 +1,172 @@ +/* + * This is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2021 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Uses pins.h & pins.c to create board (MCU package) specific 'machine_led_obj' array. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "extmod/virtpin.h" +#include "modmachine.h" +#include "pins.h" // boards// + +// ASF4 (MCU package specific pin defs in 'boards') +#include "hal_gpio.h" +#include "hpl_gpio.h" +#include "hal_atomic.h" + +STATIC void machine_led_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_led_obj_t *self = self_in; + mp_printf(print, "LED(%u)", self->id); +} + +// LED.init(mode, *, value=None) +STATIC mp_obj_t machine_led_obj_init_helper(const machine_led_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_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); + + // set initial value (do this before configuring mode/pull) + if (args[ARG_value].u_obj != mp_const_none) { + gpio_set_pin_level(self->id, mp_obj_is_true(args[ARG_value].u_obj)); + } + + // configure mode + gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT); + + return mp_const_none; +} + +// constructor(id, ...) +mp_obj_t mp_led_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted LED object + int wanted_led = mp_obj_get_int(args[0]); + const machine_led_obj_t *self = NULL; + if (0 <= wanted_led && wanted_led < MP_ARRAY_SIZE(machine_led_obj)) { + self = (machine_led_obj_t *)&machine_led_obj[wanted_led]; + } + + // the array could be padded with 'nulls' (see other Ports). + // Will also error if the asked for LED (index) is greater than the array row size. + if (self == NULL || self->base.type == NULL) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid LED")); + } + + if (n_args > 1 || n_kw > 0) { + // mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_led_obj_init_helper(self, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(self); +} + +// fast method for getting/setting pin value +STATIC mp_obj_t machine_led_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + machine_led_obj_t *self = self_in; + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(gpio_get_pin_level(self->id)); + } else { + // set pin + bool value = mp_obj_is_true(args[0]); + gpio_set_pin_level(self->id, value); + + return mp_const_none; + } +} + +// pin.init(mode) +STATIC mp_obj_t machine_led_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_led_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_led_init_obj, 1, machine_led_obj_init); + +// pin.value([value]) +STATIC mp_obj_t machine_led_value(size_t n_args, const mp_obj_t *args) { + return machine_led_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_led_value_obj, 1, 2, machine_led_value); + +// pin.low() +STATIC mp_obj_t machine_led_low(mp_obj_t self_in) { + machine_led_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT); + gpio_set_pin_level(self->id, false); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_led_low_obj, machine_led_low); + +// pin.high() +STATIC mp_obj_t machine_led_high(mp_obj_t self_in) { + machine_led_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT); + gpio_set_pin_level(self->id, true); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_led_high_obj, machine_led_high); + +// pin.toggle() +STATIC mp_obj_t machine_led_toggle(mp_obj_t self_in) { + machine_led_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT); + gpio_toggle_pin_level(self->id); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_led_toggle_obj, machine_led_toggle); + +STATIC const mp_rom_map_elem_t machine_led_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_led_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_led_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&machine_led_low_obj) }, + { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&machine_led_high_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_led_low_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_led_high_obj) }, + { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_led_toggle_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_led_locals_dict, machine_led_locals_dict_table); + +const mp_obj_type_t machine_led_type = { + { &mp_type_type }, + .name = MP_QSTR_LED, + .print = machine_led_print, + .make_new = mp_led_make_new, + .call = machine_led_call, + .locals_dict = (mp_obj_t)&machine_led_locals_dict, +}; diff --git a/ports/samd/machine_pin.c b/ports/samd/machine_pin.c new file mode 100644 index 000000000..161a3ccdd --- /dev/null +++ b/ports/samd/machine_pin.c @@ -0,0 +1,334 @@ +/* + * This is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2021 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Uses pins.h & pins.c to create board (MCU package) specific 'machine_pin_obj' array. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "extmod/virtpin.h" +#include "modmachine.h" +#include "samd_soc.h" +#include "pins.h" // boards// + +// ASF4 (MCU package specific pin defs in 'boards') +#include "hal_gpio.h" +#include "hpl_gpio.h" +#include "hal_atomic.h" + +#define GPIO_MODE_IN (0) +#define GPIO_MODE_OUT (1) +// #define GPIO_MODE_ALT (3) + +#define GPIO_STRENGTH_2MA (0) +#define GPIO_STRENGTH_8MA (1) + +// asf4 hpl_gpio.h gpio_pull_mode + +/* +typedef struct _machine_pin_irq_obj_t { + mp_irq_obj_t base; + uint32_t flags; + uint32_t trigger; +} machine_pin_irq_obj_t; + +STATIC const mp_irq_methods_t machine_pin_irq_methods; +*/ + +STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pin_obj_t *self = self_in; + mp_printf(print, "Pin(%u)", self->id); +} + +STATIC void pin_validate_drive(bool strength) { + if (strength != GPIO_STRENGTH_2MA && strength != GPIO_STRENGTH_8MA) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid argument(s) value")); + } +} + +// Pin.init(mode, pull=None, *, value=None, drive=0). No 'alt' yet. +STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_pull, ARG_value, ARG_drive, ARG_alt }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}}, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE}}, + { MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = GPIO_STRENGTH_2MA} }, + }; + + // 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); + + // set initial value (do this before configuring mode/pull) + if (args[ARG_value].u_obj != mp_const_none) { + gpio_set_pin_level(self->id, mp_obj_is_true(args[ARG_value].u_obj)); + } + + // configure mode + if (args[ARG_mode].u_obj != mp_const_none) { + mp_int_t mode = mp_obj_get_int(args[ARG_mode].u_obj); + if (mode == GPIO_MODE_IN) { + gpio_set_pin_direction(self->id, GPIO_DIRECTION_IN); + } else if (mode == GPIO_MODE_OUT) { + gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT); + } else { + gpio_set_pin_direction(self->id, GPIO_DIRECTION_IN); // If no args are given, the Pin is 'input'. + } + } + // configure pull. Only to be used with IN mode. The function sets the pin to INPUT. + uint32_t pull = 0; + mp_int_t mode = mp_obj_get_int(args[ARG_mode].u_obj); + if (mode == GPIO_MODE_OUT && args[ARG_pull].u_obj != mp_const_none) { + mp_raise_ValueError(MP_ERROR_TEXT("OUT incompatible with pull")); + } else if (args[ARG_pull].u_obj != mp_const_none) { + pull = mp_obj_get_int(args[ARG_pull].u_obj); + gpio_set_pin_pull_mode(self->id, pull); // hal_gpio.h + } + + // get the strength + bool strength = args[3].u_int; + pin_validate_drive(strength); + + return mp_const_none; +} + +// constructor(id, ...) +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted pin object + int wanted_pin = mp_obj_get_int(args[0]); + + const machine_pin_obj_t *self = NULL; + if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) { + self = (machine_pin_obj_t *)&machine_pin_obj[wanted_pin]; + } + + if (self == NULL || self->base.type == NULL) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid pin")); + } + self = (machine_pin_obj_t *)&machine_pin_obj[wanted_pin]; + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(self); +} + +// fast method for getting/setting pin value +STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + machine_pin_obj_t *self = self_in; + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(gpio_get_pin_level(self->id)); + } else { + // set pin + bool value = mp_obj_is_true(args[0]); + gpio_set_pin_level(self->id, value); + + return mp_const_none; + } +} + +// Pin.init(mode, pull) +STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); + +// Pin.value([value]) +STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) { + return machine_pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value); + +// Pin.disable(pin) +STATIC mp_obj_t machine_pin_disable(mp_obj_t self_in) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_set_pin_direction(self->id, GPIO_DIRECTION_OFF); // Disables the pin (low power state) + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_disable_obj, machine_pin_disable); + +// Pin.low() Totem-pole (push-pull) +STATIC mp_obj_t machine_pin_low(mp_obj_t self_in) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT); + gpio_set_pin_level(self->id, false); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_low_obj, machine_pin_low); + +// Pin.high() Totem-pole (push-pull) +STATIC mp_obj_t machine_pin_high(mp_obj_t self_in) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT); + gpio_set_pin_level(self->id, true); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high); + +// Pin.toggle(). Only TOGGLE pins set as OUTPUT. +STATIC mp_obj_t machine_pin_toggle(mp_obj_t self_in) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // Determine DIRECTION of PIN. + bool pin_dir; + + pin_dir = (PORT->Group[(enum gpio_port)GPIO_PORT(self->id)].DIR.reg // Get PORT# + & (1 << GPIO_PIN(self->id))) // Isolate the Pin in question + >> GPIO_PIN(self->id); // Shift to LSB for binary result. + + if (pin_dir) { + // Pin is OUTPUT + gpio_set_pin_direction(self->id, GPIO_DIRECTION_OUT); + gpio_toggle_pin_level(self->id); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("Cannot TOGGLE INPUT pin!\n")); + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_toggle_obj, machine_pin_toggle); + +// Pin.drive(). Normal (0) is 2mA, High (1) allows 8mA. +STATIC mp_obj_t machine_pin_drive(size_t n_args, const mp_obj_t *args) { + machine_pin_obj_t *self = args[0]; // Pin + if (n_args == 1) { + return mp_const_none; + } else { + bool strength = mp_obj_get_int(args[1]); // 0 or 1 + pin_validate_drive(strength); + // Set the DRVSTR bit (ASF hri/hri_port_dxx.h + hri_port_write_PINCFG_DRVSTR_bit(PORT, + (enum gpio_port)GPIO_PORT(self->id), + GPIO_PIN(self->id), + strength); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_drive_obj, 1, 2, machine_pin_drive); + +STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&machine_pin_low_obj) }, + { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&machine_pin_high_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_low_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_high_obj) }, + { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_pin_toggle_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&machine_pin_disable_obj) }, + { MP_ROM_QSTR(MP_QSTR_drive), MP_ROM_PTR(&machine_pin_drive_obj) }, + + + // { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_IN) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_OUT) }, + // { MP_ROM_QSTR(MP_QSTR_ALT), MP_ROM_INT(GPIO_MODE_ALT) }, + { MP_ROM_QSTR(MP_QSTR_PULL_OFF), MP_ROM_INT(GPIO_PULL_OFF) }, + { 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_LOW_POWER), MP_ROM_INT(GPIO_STRENGTH_2MA) }, + { MP_ROM_QSTR(MP_QSTR_HIGH_POWER), MP_ROM_INT(GPIO_STRENGTH_8MA) }, + // { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_IRQ_EDGE_RISE) }, + // { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_IRQ_EDGE_FALL) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); + +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + machine_pin_obj_t *self = self_in; + + switch (request) { + case MP_PIN_READ: { + return gpio_get_pin_level(self->id); + } + case MP_PIN_WRITE: { + gpio_set_pin_level(self->id, arg); + return 0; + } + } + return -1; +} + +STATIC const mp_pin_p_t pin_pin_p = { + .ioctl = pin_ioctl, +}; + +const mp_obj_type_t machine_pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = machine_pin_print, + .make_new = mp_pin_make_new, + .call = machine_pin_call, + .protocol = &pin_pin_p, + .locals_dict = (mp_obj_t)&machine_pin_locals_dict, +}; + +/* +STATIC mp_uint_t machine_pin_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_obj[self->id]); + gpio_set_irq_enabled(self->id, GPIO_IRQ_ALL, false); + irq->flags = 0; + irq->trigger = new_trigger; + gpio_set_irq_enabled(self->id, new_trigger, true); + return 0; +} + +STATIC mp_uint_t machine_pin_irq_info(mp_obj_t self_in, mp_uint_t info_type) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_obj[self->id]); + if (info_type == MP_IRQ_INFO_FLAGS) { + return irq->flags; + } else if (info_type == MP_IRQ_INFO_TRIGGERS) { + return irq->trigger; + } + return 0; +} + +STATIC const mp_irq_methods_t machine_pin_irq_methods = { + .trigger = machine_pin_irq_trigger, + .info = machine_pin_irq_info, +}; +*/ + +mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t obj) { + if (!mp_obj_is_type(obj, &machine_pin_type)) { + mp_raise_ValueError(MP_ERROR_TEXT("expecting a Pin")); + } + machine_pin_obj_t *pin = MP_OBJ_TO_PTR(obj); + return pin->id; +} diff --git a/ports/samd/main.c b/ports/samd/main.c index 5d84a9e88..63fe4013a 100644 --- a/ports/samd/main.c +++ b/ports/samd/main.c @@ -41,9 +41,13 @@ void samd_main(void) { 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); + + // Execute _boot.py to set up the filesystem. + pyexec_frozen_module("_boot.py"); + + // Execute user scripts. + pyexec_file_if_exists("boot.py"); + pyexec_file_if_exists("main.py"); for (;;) { if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { @@ -69,10 +73,13 @@ void gc_collect(void) { gc_collect_end(); } +/* mp_lexer_t *mp_lexer_new_from_file(const char *filename) { mp_raise_OSError(MP_ENOENT); } +*/ +#if !MICROPY_VFS mp_import_stat_t mp_import_stat(const char *path) { return MP_IMPORT_STAT_NO_EXIST; } @@ -81,6 +88,7 @@ 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); +#endif void nlr_jump_fail(void *val) { for (;;) { diff --git a/ports/samd/modmachine.c b/ports/samd/modmachine.c index 207e4c71c..0ebb5581c 100644 --- a/ports/samd/modmachine.c +++ b/ports/samd/modmachine.c @@ -27,6 +27,13 @@ #include "py/runtime.h" #include "extmod/machine_mem.h" #include "samd_soc.h" +#include "modmachine.h" + +// ASF 4 +#include "hal_flash.h" +#include "hal_init.h" +#include "hpl_gclk_base.h" +#include "hpl_pm_base.h" #if defined(MCU_SAMD21) #define DBL_TAP_ADDR ((volatile uint32_t *)(0x20000000 + 32 * 1024 - 4)) @@ -36,6 +43,9 @@ #define DBL_TAP_MAGIC_LOADER 0xf01669ef #define DBL_TAP_MAGIC_RESET 0xf02669ef +MP_DEFINE_CONST_FUN_OBJ_0(machine_uart_init_obj, machine_uart_init); +MP_DEFINE_CONST_FUN_OBJ_0(machine_uart_deinit_obj, machine_uart_deinit); + STATIC mp_obj_t machine_reset(void) { *DBL_TAP_ADDR = DBL_TAP_MAGIC_RESET; NVIC_SystemReset(); @@ -55,6 +65,49 @@ STATIC mp_obj_t machine_freq(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq); +STATIC mp_obj_t machine_unique_id(void) { + // Each device has a unique 128-bit serial number which is a concatenation of four 32-bit + // words contained at the following addresses. The uniqueness of the serial number is + // guaranteed only when using all 128 bits. + // Atmel SAM D21E / SAM D21G / SAM D21J + // SMART ARM-Based Microcontroller + // DATASHEET + // 9.6 (SAMD51) or 9.3.3 (or 10.3.3 depending on which manual)(SAMD21) Serial Number + // + // EXAMPLE (SAMD21) + // ---------------- + // OpenOCD: + // Word0: + // > at91samd21g18.cpu mdw 0x0080A00C 1 + // 0x0080a00c: 6e27f15f + // Words 1-3: + // > at91samd21g18.cpu mdw 0x0080A040 3 + // 0x0080a040: 50534b54 332e3120 ff091645 + // + // MicroPython (this code and same order as shown in Arduino IDE) + // >>> ubinascii.hexlify(machine.unique_id()) + // b'6e27f15f50534b54332e3120ff091645' + + #if defined(MCU_SAMD21) + uint32_t *id_addresses[4] = {(uint32_t *)0x0080A00C, (uint32_t *)0x0080A040, + (uint32_t *)0x0080A044, (uint32_t *)0x0080A048}; + #elif defined(MCU_SAMD51) + uint32_t *id_addresses[4] = {(uint32_t *)0x008061FC, (uint32_t *)0x00806010, + (uint32_t *)0x00806014, (uint32_t *)0x00806018}; + #endif + uint8_t raw_id[16]; + + for (int i = 0; i < 4; i++) { + for (int k = 0; k < 4; k++) { + // 'Reverse' the read bytes into a 32 bit word (Consistent with Arduino) + raw_id[4 * i + k] = (*(id_addresses[i]) >> (24 - k * 8)) & 0xff; + } + } + + return mp_obj_new_bytes((byte *)&raw_id, sizeof(raw_id)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); + 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) }, @@ -63,6 +116,11 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_uart_init), MP_ROM_PTR(&machine_uart_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_uart_deinit), MP_ROM_PTR(&machine_uart_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&machine_led_type) }, }; STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); diff --git a/ports/samd/modmachine.h b/ports/samd/modmachine.h new file mode 100644 index 000000000..61bd2f4d2 --- /dev/null +++ b/ports/samd/modmachine.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_SAMD_MODMACHINE_H +#define MICROPY_INCLUDED_SAMD_MODMACHINE_H + +#include "py/obj.h" + +extern const mp_obj_type_t machine_pin_type; +extern const mp_obj_type_t machine_led_type; + +mp_obj_t machine_uart_init(void); +mp_obj_t machine_uart_deinit(void); + +#endif // MICROPY_INCLUDED_SAMD_MODMACHINE_H diff --git a/ports/samd/modsamd.c b/ports/samd/modsamd.c new file mode 100644 index 000000000..1f9149808 --- /dev/null +++ b/ports/samd/modsamd.c @@ -0,0 +1,41 @@ +/* + * 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 "samd_soc.h" + +extern const mp_obj_type_t samd_flash_type; + +STATIC const mp_rom_map_elem_t samd_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_samd) }, + { MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&samd_flash_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(samd_module_globals, samd_module_globals_table); + +const mp_obj_module_t mp_module_samd = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&samd_module_globals, +}; diff --git a/ports/samd/modules/_boot.py b/ports/samd/modules/_boot.py new file mode 100644 index 000000000..84b02480b --- /dev/null +++ b/ports/samd/modules/_boot.py @@ -0,0 +1,17 @@ +import gc +import uos +import samd + +samd.Flash.flash_init() +bdev = samd.Flash() + +# Try to mount the filesystem, and format the flash if it doesn't exist. +try: + vfs = uos.VfsLfs1(bdev) +except: + uos.VfsLfs1.mkfs(bdev) + vfs = uos.VfsLfs1(bdev) +uos.mount(vfs, "/") + +gc.collect() +del uos, vfs, gc diff --git a/ports/samd/moduos.c b/ports/samd/moduos.c new file mode 100644 index 000000000..b884d5e7b --- /dev/null +++ b/ports/samd/moduos.c @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "extmod/vfs_lfs.h" + +STATIC const mp_rom_map_elem_t os_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, + + #if MICROPY_VFS + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + #endif + + // The following are MicroPython extensions. + + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + #endif + + #if MICROPY_VFS + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_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 +}; +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t mp_module_uos = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&os_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_uos, mp_module_uos, MICROPY_PY_UOS); diff --git a/ports/samd/modutime.c b/ports/samd/modutime.c index 8d6a40594..2d5ed0776 100644 --- a/ports/samd/modutime.c +++ b/ports/samd/modutime.c @@ -24,11 +24,64 @@ * THE SOFTWARE. */ +#include "py/runtime.h" #include "extmod/utime_mphal.h" +#include "shared/timeutils/timeutils.h" + +// localtime([secs]) +STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { + timeutils_struct_time_t tm; + mp_int_t seconds; + if (n_args == 0 || args[0] == mp_const_none) { + // seconds = pyb_rtc_get_us_since_epoch() / 1000 / 1000; + seconds = mp_obj_get_int(args[0]); + } else { + seconds = mp_obj_get_int(args[0]); + } + timeutils_seconds_since_epoch_to_struct_time(seconds, &tm); + mp_obj_t tuple[8] = { + tuple[0] = mp_obj_new_int(tm.tm_year), + tuple[1] = mp_obj_new_int(tm.tm_mon), + tuple[2] = mp_obj_new_int(tm.tm_mday), + tuple[3] = mp_obj_new_int(tm.tm_hour), + tuple[4] = mp_obj_new_int(tm.tm_min), + tuple[5] = mp_obj_new_int(tm.tm_sec), + tuple[6] = mp_obj_new_int(tm.tm_wday), + tuple[7] = mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); + +// mktime() +STATIC mp_obj_t time_mktime(mp_obj_t tuple) { + size_t len; + mp_obj_t *elem; + mp_obj_get_array(tuple, &len, &elem); + + // localtime generates a tuple of len 8. CPython uses 9, so we accept both. + if (len < 8 || len > 9) { + mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9 (%d given)"), len); + } + + return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), + mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]), + mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); + +// time() +STATIC mp_obj_t time_time(void) { + mp_raise_NotImplementedError("time"); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); STATIC const mp_rom_map_elem_t time_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + { MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) }, { MP_ROM_QSTR(MP_QSTR_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) }, @@ -37,6 +90,7 @@ STATIC const mp_rom_map_elem_t time_module_globals_table[] = { { 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) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, }; STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); diff --git a/ports/samd/mpconfigport.h b/ports/samd/mpconfigport.h index 852d9e9ee..645f16b3f 100644 --- a/ports/samd/mpconfigport.h +++ b/ports/samd/mpconfigport.h @@ -48,7 +48,12 @@ #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) #define MICROPY_CPYTHON_COMPAT (0) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT samd_help_text +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +// fixes sys/usys import issue +#define MICROPY_MODULE_WEAK_LINKS (1) // Control over Python builtins #define MICROPY_PY_ASYNC_AWAIT (0) #define MICROPY_PY_BUILTINS_STR_COUNT (0) @@ -59,17 +64,44 @@ #define MICROPY_PY_BUILTINS_ENUMERATE (0) #define MICROPY_PY_BUILTINS_FILTER (0) #define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) #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 (1) +#define MICROPY_PY_SYS_PLATFORM "samd" +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) // Extended modules #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_UOS (1) +#define MICROPY_READER_VFS (1) +#define MICROPY_VFS (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UASYNCIO (1) + +// Use VfsLfs's types for fileio/textio +#define mp_type_fileio mp_type_vfs_lfs1_fileio +#define mp_type_textio mp_type_vfs_lfs1_textio + +// Use VFS's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open_obj mp_vfs_open_obj // Hooks to add builtins @@ -77,10 +109,12 @@ { 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_samd; 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_samd), MP_ROM_PTR(&mp_module_samd) }, \ { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ #define MICROPY_PORT_ROOT_POINTERS \ diff --git a/ports/samd/mphalport.c b/ports/samd/mphalport.c index a87b7d212..c19d542a8 100644 --- a/ports/samd/mphalport.c +++ b/ports/samd/mphalport.c @@ -26,6 +26,7 @@ #include "py/runtime.h" #include "py/mphal.h" +#include "py/stream.h" #include "samd_soc.h" #include "tusb.h" @@ -60,6 +61,14 @@ void mp_hal_delay_us(mp_uint_t us) { } } +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { + uintptr_t ret = 0; + if (tud_cdc_connected() && tud_cdc_available()) { + ret |= MP_STREAM_POLL_RD; + } + return ret; +} + int mp_hal_stdin_rx_chr(void) { for (;;) { if (USARTx->USART.INTFLAG.bit.RXC) { diff --git a/ports/samd/mphalport.h b/ports/samd/mphalport.h index fc7dbe94c..2bbde4390 100644 --- a/ports/samd/mphalport.h +++ b/ports/samd/mphalport.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Damien P. George + * Copyright (c) 2019-2021 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,8 +26,14 @@ #ifndef MICROPY_INCLUDED_SAMD_MPHALPORT_H #define MICROPY_INCLUDED_SAMD_MPHALPORT_H -#include +#include "py/mpconfig.h" +#include "py/ringbuf.h" +// ASF4 +#include "hal_gpio.h" + +extern int mp_interrupt_char; +extern ringbuf_t stdin_ringbuf; extern volatile uint32_t systick_ms; void mp_hal_set_interrupt_char(int c); @@ -42,4 +48,53 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { return 0; } +// C-level pin HAL + +#include "py/obj.h" + +#define MP_HAL_PIN_FMT "%u" +#define mp_hal_pin_obj_t uint + +extern uint32_t machine_pin_open_drain_mask; + +mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t pin_in); + +static inline unsigned int mp_hal_pin_name(mp_hal_pin_obj_t pin) { + return pin; +} + +static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) { + gpio_set_pin_direction(pin, GPIO_DIRECTION_IN); + machine_pin_open_drain_mask &= ~(1 << pin); +} + +static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) { + gpio_set_pin_direction(pin, GPIO_DIRECTION_OUT); + machine_pin_open_drain_mask &= ~(1 << pin); +} + +static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) { + gpio_set_pin_direction(pin, GPIO_DIRECTION_IN); + gpio_set_pin_level(pin, 0); + machine_pin_open_drain_mask |= 1 << pin; +} + +static inline int mp_hal_pin_read(mp_hal_pin_obj_t pin) { + return gpio_get_pin_level(pin); +} + +static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) { + gpio_set_pin_level(pin, v); +} + +/* +static inline void mp_hal_pin_od_low(mp_hal_pin_obj_t pin) { + gpio_set_pin_direction(pin, GPIO_DIRECTION_OUT); +} + +static inline void mp_hal_pin_od_high(mp_hal_pin_obj_t pin) { + gpio_set_pin_direction(pin, GPIO_DIRECTION_IN); +} +*/ + #endif // MICROPY_INCLUDED_SAMD_MPHALPORT_H diff --git a/ports/samd/samd_flash.c b/ports/samd/samd_flash.c new file mode 100644 index 000000000..3bccf5577 --- /dev/null +++ b/ports/samd/samd_flash.c @@ -0,0 +1,189 @@ +/* + * 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 "extmod/vfs.h" +#include "samd_soc.h" +#include "hal_flash.h" + +// ASF 4 +#include "hal_flash.h" +#include "hal_init.h" +#include "hpl_gclk_base.h" + +#if defined(MCU_SAMD21) +#include "lib/asf4/samd21/hpl/pm/hpl_pm_base.h" +#elif defined(MCU_SAMD51) +#include "lib/asf4/samd51/hpl/pm/hpl_pm_base.h" +#include "lib/asf4/samd51/hri/hri_mclk_d51.h" +#endif + +static struct flash_descriptor flash_desc; +STATIC mp_int_t BLOCK_SIZE = VFS_BLOCK_SIZE_BYTES; // Board specific: mpconfigboard.h +extern const mp_obj_type_t samd_flash_type; + +typedef struct _samd_flash_obj_t { + mp_obj_base_t base; + uint32_t flash_base; + uint32_t flash_size; +} samd_flash_obj_t; + +// Build a Flash storage at top. +STATIC samd_flash_obj_t samd_flash_obj = { + .base = { &samd_flash_type }, + .flash_base = MICROPY_HW_FLASH_STORAGE_BASE, // Board specific: mpconfigboard.h + .flash_size = MICROPY_HW_FLASH_STORAGE_BYTES, // Board specific: mpconfigboard.h +}; + +// FLASH stuff +STATIC mp_obj_t samd_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // No args required. bdev=Flash(). Start Addr & Size defined in samd_flash_obj. + mp_arg_check_num(n_args, n_kw, 0,0, false); + + // Return singleton object. + return MP_OBJ_FROM_PTR(&samd_flash_obj); +} + +// Flash init (from cctpy) +// Method is needed for when MP starts up in _boot.py +STATIC mp_obj_t samd_flash_init(void) { + #ifdef SAMD51 + hri_mclk_set_AHBMASK_NVMCTRL_bit(MCLK); + #endif + #ifdef SAMD21 + _pm_enable_bus_clock(PM_BUS_APBB, NVMCTRL); + #endif + + flash_init(&flash_desc, NVMCTRL); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(samd_flash_init_obj, samd_flash_init); + +// Function for ioctl. +STATIC mp_obj_t eraseblock(uint32_t sector_in) { + // Destination address aligned with page start to be erased. + uint32_t DEST_ADDR = sector_in; // Number of pages to be erased. + mp_int_t PAGE_SIZE = flash_get_page_size(&flash_desc); // adf4 API call + + flash_erase(&flash_desc,DEST_ADDR,(BLOCK_SIZE / PAGE_SIZE)); + + return mp_const_none; +} + +STATIC mp_obj_t samd_flash_version(void) { + printf("Flash Driver Version: %lu\n", flash_get_version()); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(samd_flash_version_obj, samd_flash_version); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(samd_flash_version_static_obj, MP_ROM_PTR(&samd_flash_version_obj)); + +STATIC mp_obj_t samd_flash_size(void) { + // ASF4 API calls + mp_int_t PAGES = flash_get_total_pages(&flash_desc); + mp_int_t PAGE_SIZE = flash_get_page_size(&flash_desc); + printf("Flash Size: %u Bytes\n", PAGES * PAGE_SIZE); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(samd_flash_size_obj, samd_flash_size); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(samd_flash_size_static_obj, MP_ROM_PTR(&samd_flash_size_obj)); + +STATIC mp_obj_t samd_flash_readblocks(size_t n_args, const mp_obj_t *args) { + uint32_t offset = (mp_obj_get_int(args[1]) * BLOCK_SIZE) + samd_flash_obj.flash_base; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE); + if (n_args == 4) { + offset += mp_obj_get_int(args[3]); + } + + // Read data to flash (adf4 API) + flash_read(&flash_desc,offset,bufinfo.buf,bufinfo.len); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(samd_flash_readblocks_obj, 3, 4, samd_flash_readblocks); + +STATIC mp_obj_t samd_flash_writeblocks(size_t n_args, const mp_obj_t *args) { + uint32_t offset = (mp_obj_get_int(args[1]) * BLOCK_SIZE) + samd_flash_obj.flash_base; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + if (n_args == 3) { + eraseblock(offset); + // TODO check return value + } else { + offset += mp_obj_get_int(args[3]); + } + // Write data to flash (adf4 API) + flash_write(&flash_desc,offset, bufinfo.buf, bufinfo.len); + // TODO check return value + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(samd_flash_writeblocks_obj, 3, 4, samd_flash_writeblocks); + +STATIC mp_obj_t samd_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { + samd_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: + samd_flash_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->flash_size / BLOCK_SIZE); + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE); + case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: { + eraseblock(mp_obj_get_int(arg_in) * BLOCK_SIZE + samd_flash_obj.flash_base); + // TODO check return value + return MP_OBJ_NEW_SMALL_INT(0); + } + default: + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(samd_flash_ioctl_obj, samd_flash_ioctl); + +STATIC const mp_rom_map_elem_t samd_flash_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_flash_version), MP_ROM_PTR(&samd_flash_version_static_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&samd_flash_size_static_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_init), MP_ROM_PTR(&samd_flash_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&samd_flash_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&samd_flash_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&samd_flash_ioctl_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(samd_flash_locals_dict, samd_flash_locals_dict_table); + +const mp_obj_type_t samd_flash_type = { + { &mp_type_type }, + .name = MP_QSTR_Flash, + .make_new = samd_flash_make_new, + .locals_dict = (mp_obj_dict_t *)&samd_flash_locals_dict, +}; diff --git a/ports/samd/samd_soc.c b/ports/samd/samd_soc.c index a08d0de26..7f4df1bb1 100644 --- a/ports/samd/samd_soc.c +++ b/ports/samd/samd_soc.c @@ -1,6 +1,12 @@ /* * This file is part of the MicroPython project, http://micropython.org/ * + * This file initialises the USB (tinyUSB) and USART (SERCOM). Board USART settings + * are set in 'boards//mpconfigboard.h. + * + * IMPORTANT: Please refer to "I/O Multiplexing and Considerations" chapters + * in device datasheets for I/O Pin functions and assignments. + * * The MIT License (MIT) * * Copyright (c) 2019 Damien P. George @@ -24,56 +30,53 @@ * THE SOFTWARE. */ +#include "py/runtime.h" +#include "modmachine.h" #include "samd_soc.h" #include "tusb.h" -static void uart0_init(void) { +// "MP" macros defined in "boards/$(BOARD)/mpconfigboard.h" +mp_obj_t machine_uart_init(void) { + // Firstly, assign alternate function SERCOM PADs to GPIO pins. + PORT->Group[MP_PIN_GRP].PINCFG[MP_TX_PIN].bit.PMUXEN = 1; // Enable + PORT->Group[MP_PIN_GRP].PINCFG[MP_RX_PIN].bit.PMUXEN = 1; // Enable + PORT->Group[MP_PIN_GRP].PMUX[MP_PERIPHERAL_MUX].reg = MP_PORT_FUNC; // Sets PMUXE & PMUXO in 1 hit. + uint32_t rxpo = MP_RXPO_PAD; // 1=Pad1,3=Pad3 Rx data + uint32_t txpo = MP_TXPO_PAD; // 0=pad0,1=Pad2 Tx data + + // Initialise the clocks #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; + PM->APBCMASK.bit.MP_SERCOMx = 1; // Enable synchronous clock + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | MP_SERCOM_GCLK_ID_x_CORE; // Select multiplexer generic clock source and enable. + // Wait while it updates synchronously. 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; - + GCLK->PCHCTRL[MP_SERCOM_GCLK_ID_x_CORE].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0; + MCLK->APBBMASK.bit.MP_SERCOMx = 1; #endif + // Setup the Peripheral. + // Reset (clear) the peripheral registers. while (USARTx->USART.SYNCBUSY.bit.SWRST) { } - USARTx->USART.CTRLA.bit.SWRST = 1; + USARTx->USART.CTRLA.bit.SWRST = 1; // Reset all Registers, disable peripheral 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) + // Set the register bits as needed + // (CMODE (async),CHSIZE (8),FORM (no parity),SBMODE (1 stop) already 0). + USARTx->USART.CTRLA.reg = // USARTx = SERCOMx set in "boards/$(BOARD)/mpconfigboard.h" + SERCOM_USART_CTRLA_DORD // Data order + | SERCOM_USART_CTRLA_RXPO(rxpo) // Set Pad# + | SERCOM_USART_CTRLA_TXPO(txpo) // Set Pad# + | SERCOM_USART_CTRLA_MODE(1) // USART with internal clock ; - USARTx->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN; + USARTx->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN; // Enable Rx & Tx while (USARTx->USART.SYNCBUSY.bit.CTRLB) { } + + // Baud rate is clock dependant. #if CPU_FREQ == 8000000 uint32_t baud = 50437; // 115200 baud; 65536*(1 - 16 * 115200/8e6) #elif CPU_FREQ == 48000000 @@ -81,12 +84,26 @@ static void uart0_init(void) { #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; + USARTx->USART.BAUD.bit.BAUD = baud; // Set Baud + USARTx->USART.CTRLA.bit.ENABLE = 1; // Enable the peripheral + // Wait for the Registers to update. while (USARTx->USART.SYNCBUSY.bit.ENABLE) { } + + return mp_const_none; } +// Disconnect SERCOM from GPIO pins. (Can't SWRST, as that will totally kill USART). +mp_obj_t machine_uart_deinit(void) { + // Reset + printf("Disabling the Alt-Funct, releasing the USART pins for GPIO... \n"); + PORT->Group[MP_PIN_GRP].PINCFG[MP_TX_PIN].bit.PMUXEN = 0; // Disable + PORT->Group[MP_PIN_GRP].PINCFG[MP_RX_PIN].bit.PMUXEN = 0; // Disable + + return mp_const_none; +} + + static void usb_init(void) { // Init USB clock #if defined(MCU_SAMD21) @@ -142,21 +159,15 @@ void samd_init(void) { 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(); + machine_uart_init(); usb_init(); } diff --git a/ports/samd/samd_soc.h b/ports/samd/samd_soc.h index 5f68610e4..a07e68dbe 100644 --- a/ports/samd/samd_soc.h +++ b/ports/samd/samd_soc.h @@ -29,18 +29,6 @@ #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); diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 8ec130380..a44cdff92 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -77,7 +77,7 @@ 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)) +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx STM32H750xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ)) CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard SUPPORTS_HARDWARE_FP_SINGLE = 1 SUPPORTS_HARDWARE_FP_DOUBLE = 1 @@ -267,7 +267,9 @@ endif EXTMOD_SRC_C += $(addprefix extmod/,\ modonewire.c \ - ) + modnetwork.c \ + modusocket.c \ + ) DRIVERS_SRC_C += $(addprefix drivers/,\ bus/softspi.c \ @@ -286,6 +288,7 @@ SRC_C += \ usbd_hid_interface.c \ usbd_msc_interface.c \ mphalport.c \ + mpnetworkport.c \ mpthreadport.c \ irq.c \ pendsv.c \ @@ -329,9 +332,7 @@ SRC_C += \ modstm.c \ moduos.c \ modutime.c \ - modusocket.c \ network_lan.c \ - modnetwork.c \ extint.c \ usrsw.c \ rng.c \ @@ -423,13 +424,23 @@ HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal_dma_ex.c \ hal_dcmi.c \ ) +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4)) +# HAL F4-1.16.0 has a bug with missing parentheses in HAL_MMC_Erase. +# This function is unused so let the error go by as a warning. +$(BUILD)/$(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_hal_mmc.o: CFLAGS += -Wno-error=parentheses +endif endif -ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx)) +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx STM32H750xx STM32H7A3xx STM32H7A3xxQ STM32H7B3xx STM32H7B3xxQ)) HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c) else -ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 h7 l4)) +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 f4 f7 h7)) HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c) +else +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),l4)) +HAL_SRC_C += $(addprefix $(HAL_DIR)/Src/Legacy/stm32$(MCU_SERIES)xx_, hal_can.c) +$(BUILD)/$(HAL_DIR)/Src/Legacy/stm32$(MCU_SERIES)xx_hal_can.o: CFLAGS += -Wno-error=cpp +endif endif endif @@ -600,17 +611,10 @@ $(TOP)/lib/stm32lib/README.md: $(ECHO) "stm32lib submodule not found, fetching it now..." (cd $(TOP) && git submodule update --init lib/stm32lib) -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_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). +ifneq ($(FROZEN_MANIFEST),) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +CFLAGS += -DMICROPY_MODULE_FROZEN_STR endif define RUN_DFU diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 09cd3306b..3e61abce3 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -55,7 +55,11 @@ #define PIN_ADC_MASK PIN_ADC1 #define pin_adc_table pin_adc1 -#if defined(STM32H7) +#if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \ + defined(STM32H7B3xx) || defined(STM32H7B3xxQ) +#define ADCALLx (ADC2) +#define pin_adcall_table pin_adc2 +#elif defined(STM32H7) // On the H7 ADC3 is used for ADCAll to be able to read internal // channels. For all other GPIO channels, ADC12 is used instead. #define ADCALLx (ADC3) @@ -129,14 +133,18 @@ #elif defined(STM32F411xE) || defined(STM32F412Zx) || \ defined(STM32F413xx) || defined(STM32F427xx) || \ defined(STM32F429xx) || defined(STM32F437xx) || \ - defined(STM32F439xx) || defined(STM32F446xx) + defined(STM32F439xx) || defined(STM32F446xx) || \ + defined(STM32F479xx) #define VBAT_DIV (4) #elif defined(STM32F722xx) || defined(STM32F723xx) || \ defined(STM32F732xx) || defined(STM32F733xx) || \ defined(STM32F746xx) || defined(STM32F765xx) || \ defined(STM32F767xx) || defined(STM32F769xx) #define VBAT_DIV (4) -#elif defined(STM32H743xx) || defined(STM32H747xx) +#elif defined(STM32H743xx) || defined(STM32H747xx) || \ + defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \ + defined(STM32H7B3xx) || defined(STM32H7B3xxQ) || \ + defined(STM32H750xx) #define VBAT_DIV (4) #elif defined(STM32L432xx) || \ defined(STM32L451xx) || defined(STM32L452xx) || \ @@ -226,6 +234,9 @@ STATIC void adc_wait_for_eoc_or_timeout(ADC_HandleTypeDef *adcHandle, int32_t ti STATIC void adcx_clock_enable(ADC_HandleTypeDef *adch) { #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) ADCx_CLK_ENABLE(); + #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + __HAL_RCC_ADC12_CLK_ENABLE(); + __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP); #elif defined(STM32H7) if (adch->Instance == ADC3) { __HAL_RCC_ADC3_CLK_ENABLE(); diff --git a/ports/stm32/adc.h b/ports/stm32/adc.h index 64864b196..9101b9db8 100644 --- a/ports/stm32/adc.h +++ b/ports/stm32/adc.h @@ -44,12 +44,16 @@ static inline void adc_deselect_vbat(ADC_TypeDef *adc, uint32_t channel) { #if defined(STM32F0) || defined(STM32WB) adc_common = ADC1_COMMON; - #elif defined(STM32F4) || defined(STM32L4) + #elif defined(STM32F4) adc_common = ADC_COMMON_REGISTER(0); #elif defined(STM32F7) adc_common = ADC123_COMMON; + #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + adc_common = ADC12_COMMON; #elif defined(STM32H7) adc_common = adc == ADC3 ? ADC3_COMMON : ADC12_COMMON; + #elif defined(STM32L4) + adc_common = __LL_ADC_COMMON_INSTANCE(0); #endif adc_common->CCR &= ~LL_ADC_PATH_INTERNAL_VBAT; diff --git a/ports/stm32/boardctrl.h b/ports/stm32/boardctrl.h index 551be3453..0878a453b 100644 --- a/ports/stm32/boardctrl.h +++ b/ports/stm32/boardctrl.h @@ -28,6 +28,11 @@ #include "py/mpconfig.h" +// Additional entries for use with pendsv_schedule_dispatch. +#ifndef MICROPY_BOARD_PENDSV_ENTRIES +#define MICROPY_BOARD_PENDSV_ENTRIES +#endif + #ifndef MICROPY_BOARD_STARTUP #define MICROPY_BOARD_STARTUP powerctrl_check_enter_bootloader #endif @@ -60,6 +65,24 @@ #define MICROPY_BOARD_END_SOFT_RESET boardctrl_end_soft_reset #endif +// Called when USBD CDC data is available. +// Default function defined in usbd_cdc_interface.h. +#ifndef MICROPY_BOARD_USBD_CDC_RX_EVENT +#define MICROPY_BOARD_USBD_CDC_RX_EVENT usbd_cdc_rx_event_callback +#endif + +// Called to poll Bluetooth HCI now. +// Default function defined in mpbthciport.h. +#ifndef MICROPY_BOARD_BT_HCI_POLL_NOW +#define MICROPY_BOARD_BT_HCI_POLL_NOW mp_bluetooth_hci_poll_now_default +#endif + +// Called to poll Bluetooth HCI after the given timeout. +// Default function defined in mpbthciport.h. +#ifndef MICROPY_BOARD_BT_HCI_POLL_IN_MS +#define MICROPY_BOARD_BT_HCI_POLL_IN_MS mp_bluetooth_hci_poll_in_ms_default +#endif + // Constants to return from boardctrl_run_boot_py, boardctrl_run_main_py. enum { BOARDCTRL_CONTINUE, diff --git a/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json new file mode 100644 index 000000000..698e666f2 --- /dev/null +++ b/ports/stm32/boards/ADAFRUIT_F405_EXPRESS/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "4382-09.jpg" + ], + "mcu": "stm32f4", + "product": "F405 Express", + "thumbnail": "", + "url": "https://www.adafruit.com/product/4382", + "vendor": "Adafruit" +} diff --git a/ports/stm32/boards/B_L072Z_LRWAN1/board.json b/ports/stm32/boards/B_L072Z_LRWAN1/board.json new file mode 100644 index 000000000..e6bbe3591 --- /dev/null +++ b/ports/stm32/boards/B_L072Z_LRWAN1/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "b_l072z_lrwan1.jpg" + ], + "mcu": "stm32l0", + "product": "B_L072Z_LRWAN1", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/B_L475E_IOT01A/board.json b/ports/stm32/boards/B_L475E_IOT01A/board.json new file mode 100644 index 000000000..91e76bc08 --- /dev/null +++ b/ports/stm32/boards/B_L475E_IOT01A/board.json @@ -0,0 +1,13 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [], + "mcu": "stm32l4", + "product": "B_L475E_IOT01A", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/CERB40/board.json b/ports/stm32/boards/CERB40/board.json new file mode 100644 index 000000000..f80b3f5ca --- /dev/null +++ b/ports/stm32/boards/CERB40/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "cerb40.jpg" + ], + "mcu": "stm32f4", + "product": "CERB40", + "thumbnail": "", + "url": "", + "vendor": "" +} diff --git a/ports/stm32/boards/ESPRUINO_PICO/board.json b/ports/stm32/boards/ESPRUINO_PICO/board.json new file mode 100644 index 000000000..554687edb --- /dev/null +++ b/ports/stm32/boards/ESPRUINO_PICO/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "Pico_angled.jpg" + ], + "mcu": "stm32f4", + "product": "Pico", + "thumbnail": "", + "url": "https://www.espruino.com/Pico", + "vendor": "Espruino" +} diff --git a/ports/stm32/boards/ESPRUINO_PICO/deploy.md b/ports/stm32/boards/ESPRUINO_PICO/deploy.md new file mode 100644 index 000000000..5c85668f2 --- /dev/null +++ b/ports/stm32/boards/ESPRUINO_PICO/deploy.md @@ -0,0 +1 @@ +For programming an Espruino Pico see the "Advanced Reflashing" section of [this page](http://www.espruino.com/Pico). diff --git a/ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json b/ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json new file mode 100644 index 000000000..d02b7ece1 --- /dev/null +++ b/ports/stm32/boards/GARATRONIC_NADHAT_F405/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "garatronic_nadhat_f405.jpg" + ], + "mcu": "stm32f4", + "product": "GARATRONIC_NADHAT_F405", + "thumbnail": "", + "url": "https://shop.mchobby.be/product.php?id_product=1653", + "vendor": "McHobby" +} diff --git a/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.h b/ports/stm32/boards/GARATRONIC_NADHAT_F405/mpconfigboard.h similarity index 100% rename from ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.h rename to ports/stm32/boards/GARATRONIC_NADHAT_F405/mpconfigboard.h diff --git a/ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.mk b/ports/stm32/boards/GARATRONIC_NADHAT_F405/mpconfigboard.mk similarity index 100% rename from ports/stm32/boards/NADHAT_PYBF405/mpconfigboard.mk rename to ports/stm32/boards/GARATRONIC_NADHAT_F405/mpconfigboard.mk diff --git a/ports/stm32/boards/NADHAT_PYBF405/pins.csv b/ports/stm32/boards/GARATRONIC_NADHAT_F405/pins.csv similarity index 100% rename from ports/stm32/boards/NADHAT_PYBF405/pins.csv rename to ports/stm32/boards/GARATRONIC_NADHAT_F405/pins.csv diff --git a/ports/stm32/boards/NADHAT_PYBF405/stm32f4xx_hal_conf.h b/ports/stm32/boards/GARATRONIC_NADHAT_F405/stm32f4xx_hal_conf.h similarity index 100% rename from ports/stm32/boards/NADHAT_PYBF405/stm32f4xx_hal_conf.h rename to ports/stm32/boards/GARATRONIC_NADHAT_F405/stm32f4xx_hal_conf.h diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/board.json b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/board.json new file mode 100644 index 000000000..1df9b6f65 --- /dev/null +++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/board.json @@ -0,0 +1,13 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [], + "mcu": "stm32f4", + "product": "GARATRONIC_PYBSTICK26_F411", + "thumbnail": "", + "url": "https://shop.mchobby.be/product.php?id_product=1844", + "vendor": "McHobby" +} diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/manifest.py b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/manifest.py new file mode 100644 index 000000000..b09c7ab92 --- /dev/null +++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/manifest.py @@ -0,0 +1,2 @@ +include("$(MPY_DIR)/extmod/uasyncio/manifest.py") +freeze("$(MPY_DIR)/drivers/", ("display/ssd1306.py")) diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.h b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.h new file mode 100644 index 000000000..408bc2851 --- /dev/null +++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.h @@ -0,0 +1,84 @@ +#define MICROPY_HW_BOARD_NAME "PYBSTICK26_STD" +#define MICROPY_HW_MCU_NAME "STM32F411RE" +#define MICROPY_PY_THREAD (1) + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_KXTJ3 (0) +#define MICROPY_HW_HAS_LCD (0) +#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 16MHz +#define MICROPY_HW_CLK_PLLM (16) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_LAST_FREQ (1) + +// Pybstick26 STD has an optional 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (1) +#define MICROPY_HW_RTC_USE_CALOUT (0) + +// UART config +#define MICROPY_HW_UART1_NAME "XB" +#define MICROPY_HW_UART1_TX (pin_A15) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART2_NAME "XA" +#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_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_B8) // S5 +#define MICROPY_HW_I2C1_SDA (pin_B9) // S3 +#define MICROPY_HW_I2C2_NAME "Y" +#define MICROPY_HW_I2C2_SCL (pin_B10) //S13 +#define MICROPY_HW_I2C2_SDA (pin_B3) // S11 + +// SPI buses +#define MICROPY_HW_SPI1_NAME "X" +#define MICROPY_HW_SPI1_NSS (pin_A4) // S26 +#define MICROPY_HW_SPI1_SCK (pin_A5) // S23 +#define MICROPY_HW_SPI1_MISO (pin_B4) // S21 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // S19 +#define MICROPY_HW_SPI2_NAME "Y" +#define MICROPY_HW_SPI2_NSS (pin_B12) // S15 +#define MICROPY_HW_SPI2_SCK (pin_B13) // S16 +#define MICROPY_HW_SPI2_MISO (pin_B14) // S18 +#define MICROPY_HW_SPI2_MOSI (pin_C3) // S13 + +// USRSW has no pullup or pulldown, and pressing the switch makes the input go low +#define MICROPY_HW_USRSW_PIN (pin_C13) +#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_B0) // yellow +#define MICROPY_HW_LED4 (pin_B1) // blue +#define MICROPY_HW_LED3_PWM { TIM3, 3, TIM_CHANNEL_3, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED4_PWM { TIM3, 4, TIM_CHANNEL_4, 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 with custom SDIO pins +#define MICROPY_HW_SDCARD_D0 (pin_B7) +#define MICROPY_HW_SDCARD_D1 (pin_A8) +#define MICROPY_HW_SDCARD_D2 (pin_A9) +#define MICROPY_HW_SDCARD_D3 (pin_B5) +#define MICROPY_HW_SDCARD_CK (pin_B15) +#define MICROPY_HW_SDCARD_CMD (pin_A6) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.mk b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.mk new file mode 100644 index 000000000..df9506522 --- /dev/null +++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F411xE +AF_FILE = boards/stm32f411_af.csv +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/pins.csv b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/pins.csv new file mode 100644 index 000000000..c52e65cf7 --- /dev/null +++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/pins.csv @@ -0,0 +1,55 @@ +S1,3.3V +S2,VBUS +S3,PB9 +S4,VIN +S5,PB8 +S6,GND +S7,PB6 +S8,PA2 +S9,GND +S10,PA3 +S11,PB3 +S12,PA0 +S13,PB10 +S13A,PC3 +S14,Reset +S15,PB12 +S15A,PC5 +S16,PB13 +S16A,PC6 +S17,GND +S18,PB14 +S18A,PC7 +S19,PA7 +S20,GND +S21,PB4 +S22,PA10 +S23,PA5 +S24,PA15 +S25,GND +S26,PA4 +SW,PC13 +SW2,PB6 +LED_GREEN,PA14 +LED_YELLOW,PB0 +LED_RED,PA13 +LED_BLUE,PB1 +SD_D0,PB7 +SD_D1,PA8 +SD_D2,PA9 +SD_D3,PB5 +SD_CMD,PA6 +SD_CK,PB15 +USB_DM,PA11 +USB_DP,PA12 +OSC_IN,PH0 +OSC_OUT,PH1 +OSC32_IN,PC14 +OSC32_OUT,PC15 +QSPI_BK1_IO3,PA1 +SDIO_CMD,PA6 +SDIO_D1,PA8 +SDIO_D2,PA9 +SDIO_D3,PB5 +SDIO_D0,PB7 +SDIO_CK,PB15 diff --git a/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/stm32f4xx_hal_conf.h b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/stm32f4xx_hal_conf.h new file mode 100644 index 000000000..7d6344f0a --- /dev/null +++ b/ports/stm32/boards/GARATRONIC_PYBSTICK26_F411/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 diff --git a/ports/stm32/boards/HYDRABUS/board.json b/ports/stm32/boards/HYDRABUS/board.json new file mode 100644 index 000000000..32561e652 --- /dev/null +++ b/ports/stm32/boards/HYDRABUS/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "hydrabus.jpg" + ], + "mcu": "stm32f4", + "product": "HYDRABUS", + "thumbnail": "", + "url": "", + "vendor": "" +} diff --git a/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c b/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c index ec41fdfee..b185b579f 100644 --- a/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c +++ b/ports/stm32/boards/LEGO_HUB_NO6/bluetooth_init_cc2564C_1.5.c @@ -4,9 +4,9 @@ #if !BUILDING_MBOOT // init script created from -// - /Users/dktobthy/Downloads/cc256xc_bt_spv1.5/CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26.bts +// - CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26.bts // - AKA TIInit_6.12.26.bts -// - /Users/dktobthy/Downloads/cc256xc_bt_spv1.5/CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26_ble_add-on.bts +// - CC256XC_BT_SP/v1.5/initscripts-TIInit_6.12.26_ble_add-on.bts #include #include "lib/btstack/chipset/cc256x/btstack_chipset_cc256x.h" @@ -613,4 +613,4 @@ const uint8_t cc256x_init_script[] = { const uint32_t cc256x_init_script_size = 6771; -#endif \ No newline at end of file +#endif diff --git a/ports/stm32/boards/LEGO_HUB_NO6/board.json b/ports/stm32/boards/LEGO_HUB_NO6/board.json new file mode 100644 index 000000000..c11b9f181 --- /dev/null +++ b/ports/stm32/boards/LEGO_HUB_NO6/board.json @@ -0,0 +1,13 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [], + "mcu": "stm32f4", + "product": "Hub No.6", + "thumbnail": "", + "url": "", + "vendor": "Lego" +} diff --git a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h index b3e061efb..188cd67af 100644 --- a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h +++ b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h @@ -18,6 +18,7 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_FLASH_FS_LABEL "HUB_NO6" // HSE is 16MHz, CPU freq set to 100MHz, buses at maximum freq #define MICROPY_HW_CLK_PLLM (16) diff --git a/ports/stm32/boards/LIMIFROG/board.json b/ports/stm32/boards/LIMIFROG/board.json new file mode 100644 index 000000000..313735007 --- /dev/null +++ b/ports/stm32/boards/LIMIFROG/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "limifrog.jpg" + ], + "mcu": "stm32l4", + "product": "LIMIFROG", + "thumbnail": "", + "url": "", + "vendor": "" +} diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json b/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json new file mode 100644 index 000000000..a6cfc45b0 --- /dev/null +++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/board.json @@ -0,0 +1,17 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [ + "mikroBUS" + ], + "images": [ + "mikroe_clicker2_stm32.jpg" + ], + "mcu": "stm32f4", + "product": "MikroE Clicker 2 for STM32", + "thumbnail": "", + "url": "https://www.mikroe.com/clicker-2-stm32f4", + "vendor": "MikroElektronika" +} diff --git a/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv b/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv index 09e1ccfb4..c04d2b8c4 100644 --- a/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv +++ b/ports/stm32/boards/MIKROE_CLICKER2_STM32/pins.csv @@ -85,4 +85,4 @@ T2,PE0 T3,PA10 USB_VBUS,PA9 USB_DM,PA11 -USB_DP,PA12 \ No newline at end of file +USB_DP,PA12 diff --git a/ports/stm32/boards/MIKROE_QUAIL/bdev.c b/ports/stm32/boards/MIKROE_QUAIL/bdev.c new file mode 100644 index 000000000..7095817e4 --- /dev/null +++ b/ports/stm32/boards/MIKROE_QUAIL/bdev.c @@ -0,0 +1,28 @@ +#include "py/obj.h" +#include "storage.h" +#include "spi.h" + +#if !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE + +STATIC const spi_proto_cfg_t spi_bus = { + .spi = &spi_obj[2], // SPI3 hardware peripheral + .baudrate = 25000000, + .polarity = 0, + .phase = 0, + .bits = 8, + .firstbit = SPI_FIRSTBIT_MSB, +}; + +STATIC mp_spiflash_cache_t spi_bdev_cache; + +const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_SPI, + .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS, + .bus.u_spi.data = (void *)&spi_bus, + .bus.u_spi.proto = &spi_proto, + .cache = &spi_bdev_cache, +}; + +spi_bdev_t spi_bdev; + +#endif diff --git a/ports/stm32/boards/MIKROE_QUAIL/board.json b/ports/stm32/boards/MIKROE_QUAIL/board.json new file mode 100644 index 000000000..ccd9b4fdc --- /dev/null +++ b/ports/stm32/boards/MIKROE_QUAIL/board.json @@ -0,0 +1,18 @@ +{ + "deploy": [ + "../MIKROE_QUAIL/deploy.md" + ], + "docs": "", + "features": [ + "mikroBUS" + ], + "id": "MIKROE-QUAIL", + "images": [ + "quail_top.jpg" + ], + "mcu": "stm32f4", + "product": "MikroE Quail", + "thumbnail": "", + "url": "https://www.mikroe.com/quail", + "vendor": "MikroElektronika" +} diff --git a/ports/stm32/boards/MIKROE_QUAIL/deploy.md b/ports/stm32/boards/MIKROE_QUAIL/deploy.md new file mode 100644 index 000000000..5d6ea00a2 --- /dev/null +++ b/ports/stm32/boards/MIKROE_QUAIL/deploy.md @@ -0,0 +1,13 @@ +### Quail via DFU + +Quail can be programmed via USB with the ST DFU bootloader, using +e.g. [dfu-util](http://dfu-util.sourceforge.net/) or +[pydfu.py](https://github.com/micropython/micropython/blob/master/tools/pydfu.py). + +To enter the bootloader press and release the Reset button while holding the +Boot button. Alternatively, you can use `machine.bootloader()` from the +MicroPython REPL. + +```bash +dfu-util --alt 0 -D firmware.dfu +``` diff --git a/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.h b/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.h new file mode 100644 index 000000000..6cb6b7260 --- /dev/null +++ b/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.h @@ -0,0 +1,109 @@ +#define MICROPY_HW_BOARD_NAME "MikroE Quail" +#define MICROPY_HW_MCU_NAME "STM32F427VI" + +// 1 = use STM32 internal flash (1 MByte) +// 0 = use onboard external SPI flash (8 MByte) +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) + +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_HAS_FLASH (1) + +// HSE is 12MHz +#define MICROPY_HW_CLK_PLLM (6) +#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4) +#define MICROPY_HW_CLK_PLLQ (14) +#define MICROPY_HW_CLK_LAST_FREQ (1) + +// The board has no crystal for the RTC +#define MICROPY_HW_RTC_USE_LSE (0) +#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_UART3_NAME "SLOT1" +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +// mikroBUS slot 2 +#define MICROPY_HW_UART2_NAME "SLOT2" +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +// mikroBUS slot 3 +#define MICROPY_HW_UART6_NAME "SLOT3" +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) +// mikroBUS slot 4 +#define MICROPY_HW_UART1_NAME "SLOT4" +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) + +// I2C buses +// mikroBUS slot 1, 2, 3, 4, and header +#define MICROPY_HW_I2C1_NAME "SLOT1234H" +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) + +// SPI buses +// mikroBUS slot 1, 2, and header +#define MICROPY_HW_SPI1_NAME "SLOT12H" +#define MICROPY_HW_SPI1_SCK (pin_B3) +#define MICROPY_HW_SPI1_MISO (pin_B4) +#define MICROPY_HW_SPI1_MOSI (pin_B5) +// mikroBUS slot 3, 4, and FLASH +#define MICROPY_HW_SPI3_NAME "SLOT34F" +#define MICROPY_HW_SPI3_SCK (pin_C10) +#define MICROPY_HW_SPI3_MISO (pin_C11) +#define MICROPY_HW_SPI3_MOSI (pin_C12) + +// LEDs +#define MICROPY_HW_LED1 (pin_E15) // orange +#define MICROPY_HW_LED2 (pin_E10) // green +#define MICROPY_HW_LED3 (pin_C3) // 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) + +// External SPI Flash config (Cypress S25FL164K) +#if !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE + +#define MICROPY_HW_SPIFLASH_SIZE_BITS (64 * 1024 * 1024) // 64 Mbit (8 MByte) + +#define MICROPY_HW_SPIFLASH_CS (pin_A13) +#define MICROPY_HW_SPIFLASH_SCK (MICROPY_HW_SPI3_SCK) +#define MICROPY_HW_SPIFLASH_MISO (MICROPY_HW_SPI3_MISO) +#define MICROPY_HW_SPIFLASH_MOSI (MICROPY_HW_SPI3_MOSI) + +extern const struct _mp_spiflash_config_t spiflash_config; +extern struct _spi_bdev_t spi_bdev; +#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1) +#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)) +#define MICROPY_HW_BDEV_SPIFLASH_EXTENDED (&spi_bdev) // for extended block protocol + +#endif // !MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE + +// Bootloader configuration (only needed if Mboot is used) +#define MBOOT_I2C_PERIPH_ID 1 +#define MBOOT_I2C_SCL (pin_B6) +#define MBOOT_I2C_SDA (pin_B7) +#define MBOOT_I2C_ALTFUNC (4) +#define MBOOT_FSLOAD (1) +#define MBOOT_VFS_FAT (1) + +#define MBOOT_SPIFLASH_ADDR (0x80000000) +#define MBOOT_SPIFLASH_BYTE_SIZE (8 * 1024 * 1024) +#define MBOOT_SPIFLASH_LAYOUT "/0x80000000/512*8Kg" +#define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE \ + (8 / 4) // 8k page, 4k erase block +#define MBOOT_SPIFLASH_CONFIG (&spiflash_config) +#define MBOOT_SPIFLASH_SPIFLASH (&spi_bdev.spiflash) diff --git a/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.mk b/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.mk new file mode 100644 index 000000000..12f4f5798 --- /dev/null +++ b/ports/stm32/boards/MIKROE_QUAIL/mpconfigboard.mk @@ -0,0 +1,10 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F427xx +LD_FILES = boards/stm32f427xi.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 + +# According to the datasheet, page 75, table 12, the alternate functions +# of STM32F427xx and STM32F429xx are exactly the same. +# See https://www.st.com/resource/en/datasheet/stm32f427vi.pdf. +AF_FILE = boards/stm32f429_af.csv diff --git a/ports/stm32/boards/MIKROE_QUAIL/pins.csv b/ports/stm32/boards/MIKROE_QUAIL/pins.csv new file mode 100644 index 000000000..41868cf72 --- /dev/null +++ b/ports/stm32/boards/MIKROE_QUAIL/pins.csv @@ -0,0 +1,120 @@ +# Pin mapping for board MikroElektronika Quail, based on CPU STM32F427VIT6 + +### mikroBUS ########################### + +# Slot 1 (SPI1, UART3, I2C1) +MB1_AN,PA6 +MB1_RST,PA2 +MB1_CS,PA3 +MB1_SCK,PB3 +MB1_MISO,PB4 +MB1_MOSI,PB5 +MB1_PWM,PE9 +MB1_INT,PA1 +MB1_RX,PD9 +MB1_TX,PD8 +MB1_SCL,PB6 +MB1_SDA,PB7 + +# Slot 2 (SPI1, UART2, I2C1) +MB2_AN,PA4 +MB2_RST,PE1 +MB2_CS,PE0 +MB2_SCK,PB3 +MB2_MISO,PB4 +MB2_MOSI,PB5 +MB2_PWM,PD15 +MB2_INT,PB9 +MB2_RX,PD6 +MB2_TX,PD5 +MB2_SCL,PB6 +MB2_SDA,PB7 + +# Slot 3 (SPI3, UART6, I2C1) +MB3_AN,PA7 +MB3_RST,PD8 +MB3_CS,PD11 +MB3_SCK,PC10 +MB3_MISO,PC11 +MB3_MOSI,PC12 +MB3_PWM,PD13 +MB3_INT,PC8 +MB3_RX,PC7 +MB3_TX,PC6 +MB3_SCL,PB6 +MB3_SDA,PB7 + +# Slot 4 (SPI3, UART1, I2C1) +MB4_AN,PA5 +MB4_RST,PD0 +MB4_CS,PD1 +MB4_SCK,PC10 +MB4_MISO,PC11 +MB4_MOSI,PC12 +MB4_PWM,PD14 +MB4_INT,PA14 +MB4_RX,PA10 +MB4_TX,PA9 +MB4_SCL,PB6 +MB4_SDA,PB7 + + +### Edge Contacts ###################### + +,PC5 +,PB0 +,PE7 +,PE8 + +,PE11 +,PC4 +,PE13 +,PE14 + +,PB10 +,PB11 +,PB12 +,PB13 + +# I2C1 +,PB6 +,PB7 + +# SPI3 +,PC10 +,PC11 +,PC12 +,PD10 + +,PA15 +,PC13 +,PE6 +,PE5 + +,PD2 +,PD3 +,PD4 +,PD7 + +,PE2 +,PE3 +,PE4 + + +### FLASH Memory ####################### + +# Spansion S25FL164K - SPI3 +FLASH_CS,PA13 + + +### LED ################################ + +LED1,PE15 +LED2,PE10 +LED3,PC3 + + +### Micro USB ########################## + +,-PA11 +,-PA12 diff --git a/ports/stm32/boards/MIKROE_QUAIL/stm32f4xx_hal_conf.h b/ports/stm32/boards/MIKROE_QUAIL/stm32f4xx_hal_conf.h new file mode 100644 index 000000000..b8b935915 --- /dev/null +++ b/ports/stm32/boards/MIKROE_QUAIL/stm32f4xx_hal_conf.h @@ -0,0 +1,18 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * The MIT License (MIT) + * Copyright (c) 2021 Lorenzo Cappelletti + */ +#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 EXTERNAL_CLOCK_VALUE (12288000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (0) + +#endif // MICROPY_INCLUDED_STM32F4XX_HAL_CONF_H diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/board.json b/ports/stm32/boards/NETDUINO_PLUS_2/board.json new file mode 100644 index 000000000..044bc2736 --- /dev/null +++ b/ports/stm32/boards/NETDUINO_PLUS_2/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "netduino_plus_2.jpg" + ], + "mcu": "stm32f4", + "product": "NETDUINO_PLUS_2", + "thumbnail": "", + "url": "", + "vendor": "" +} diff --git a/ports/stm32/boards/NUCLEO_F091RC/board.json b/ports/stm32/boards/NUCLEO_F091RC/board.json new file mode 100644 index 000000000..a28f9b0a6 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F091RC/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f091rc.jpg" + ], + "mcu": "stm32f0", + "product": "Nucleo F091RC", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h index a0bff5996..7df86d75f 100644 --- a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h @@ -13,7 +13,6 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_ADC (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_HAS_SWITCH (1) // For system clock, enable one source: diff --git a/ports/stm32/boards/NUCLEO_F401RE/board.json b/ports/stm32/boards/NUCLEO_F401RE/board.json new file mode 100644 index 000000000..15eae0fe2 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F401RE/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f401re.jpg" + ], + "mcu": "stm32f4", + "product": "Nucleo F401RE", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h index 6b874e298..8dda34f4a 100644 --- a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F401RE/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_SERVO (1) // HSE is 8MHz, HSI is 16MHz CPU freq set to 84MHz // Default source for the clock is HSI. diff --git a/ports/stm32/boards/NUCLEO_F411RE/board.json b/ports/stm32/boards/NUCLEO_F411RE/board.json new file mode 100644 index 000000000..a428b8988 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F411RE/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f411re.jpg" + ], + "mcu": "stm32f4", + "product": "Nucleo F411RE", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h index e37ce889c..a883ffb3e 100644 --- a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F411RE/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_SERVO (1) // HSE is 8MHz, CPU freq set to 96MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/NUCLEO_F412ZG/board.json b/ports/stm32/boards/NUCLEO_F412ZG/board.json new file mode 100644 index 000000000..48a717ec0 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F412ZG/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f412zg.jpg" + ], + "mcu": "stm32f4", + "product": "Nucleo F412ZG", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.h index 2a557f135..df661985d 100644 --- a/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F412ZG/mpconfigboard.h @@ -6,6 +6,7 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) // HSE is 8MHz, CPU freq set to 96MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/NUCLEO_F412ZG/pins.csv b/ports/stm32/boards/NUCLEO_F412ZG/pins.csv index 430d0972b..31dcb99ed 100644 --- a/ports/stm32/boards/NUCLEO_F412ZG/pins.csv +++ b/ports/stm32/boards/NUCLEO_F412ZG/pins.csv @@ -115,4 +115,4 @@ PH1,PH1 SW,C13 LED_RED,B14 LED_GREEN,B0 -LED_BLUE,B7 \ No newline at end of file +LED_BLUE,B7 diff --git a/ports/stm32/boards/NUCLEO_F413ZH/board.json b/ports/stm32/boards/NUCLEO_F413ZH/board.json new file mode 100644 index 000000000..218998852 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F413ZH/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f413zh.jpg" + ], + "mcu": "stm32f4", + "product": "Nucleo F413ZH", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h index 5297ceda5..621132137 100644 --- a/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F413ZH/mpconfigboard.h @@ -3,10 +3,13 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE_SEGMENT2 (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_SERVO (1) // HSE is 8MHz, CPU freq set to 96MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/board.json b/ports/stm32/boards/NUCLEO_F429ZI/board.json new file mode 100644 index 000000000..60a8795f4 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F429ZI/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f429zi.jpg" + ], + "mcu": "stm32f4", + "product": "Nucleo F429ZI", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h index 86c02b517..76f075546 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -6,6 +6,7 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/NUCLEO_F439ZI/board.json b/ports/stm32/boards/NUCLEO_F439ZI/board.json new file mode 100644 index 000000000..7ee717d02 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F439ZI/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f439zi.jpg" + ], + "mcu": "stm32f4", + "product": "Nucleo F439ZI", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h index 010e3b1f5..4d5050b1b 100644 --- a/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F439ZI/mpconfigboard.h @@ -3,9 +3,12 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE_SEGMENT2 (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) // HSE is 8MHz from ST-LINK, in bypass mode, run SYSCLK at 168MHz #define MICROPY_HW_CLK_USE_BYPASS (1) diff --git a/ports/stm32/boards/NUCLEO_F446RE/board.json b/ports/stm32/boards/NUCLEO_F446RE/board.json new file mode 100644 index 000000000..93b65e89d --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F446RE/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f446re.jpg" + ], + "mcu": "stm32f4", + "product": "Nucleo F446RE", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h index 681231578..88bfd39b4 100644 --- a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.h @@ -5,6 +5,7 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_SERVO (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 diff --git a/ports/stm32/boards/NUCLEO_F722ZE/board.json b/ports/stm32/boards/NUCLEO_F722ZE/board.json new file mode 100644 index 000000000..e44ef8c10 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F722ZE/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f722ze.jpg" + ], + "mcu": "stm32f7", + "product": "Nucleo F722ZE", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F746ZG/board.json b/ports/stm32/boards/NUCLEO_F746ZG/board.json new file mode 100644 index 000000000..0459c3a13 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F746ZG/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f746zg.jpg" + ], + "mcu": "stm32f7", + "product": "Nucleo F746ZG", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_F767ZI/board.json b/ports/stm32/boards/NUCLEO_F767ZI/board.json new file mode 100644 index 000000000..c05d1a1c0 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F767ZI/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_f767zi.jpg" + ], + "mcu": "stm32f7", + "product": "Nucleo F767ZI", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_H743ZI/board.json b/ports/stm32/boards/NUCLEO_H743ZI/board.json new file mode 100644 index 000000000..4e92b6184 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_h743zi.jpg" + ], + "mcu": "stm32h7", + "product": "Nucleo H743ZI", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk index ce8f83e57..8a16c2f01 100644 --- a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk @@ -7,17 +7,17 @@ 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 +# When using Mboot everything goes after the bootloader +LD_FILES = boards/stm32h743.ld boards/common_bl.ld +TEXT0_ADDR = 0x08020000 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 +# When not using Mboot everything goes at the start of flash +LD_FILES = boards/stm32h743.ld boards/common_basic.ld TEXT0_ADDR = 0x08000000 -TEXT1_ADDR = 0x08040000 endif # MicroPython settings MICROPY_PY_LWIP = 1 MICROPY_PY_USSL = 1 MICROPY_SSL_MBEDTLS = 1 +MICROPY_VFS_LFS2 = 1 diff --git a/ports/stm32/boards/NUCLEO_H743ZI2/board.json b/ports/stm32/boards/NUCLEO_H743ZI2/board.json new file mode 100644 index 000000000..30361e6f1 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI2/board.json @@ -0,0 +1,13 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [], + "mcu": "stm32", + "product": "Nucleo H743ZI2", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_L073RZ/board.json b/ports/stm32/boards/NUCLEO_L073RZ/board.json new file mode 100644 index 000000000..949d16678 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L073RZ/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_l073rz.jpg" + ], + "mcu": "stm32l0", + "product": "Nucleo L073RZ", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_L432KC/board.json b/ports/stm32/boards/NUCLEO_L432KC/board.json new file mode 100644 index 000000000..60f96f71e --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L432KC/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_l432kc.jpg" + ], + "mcu": "stm32l4", + "product": "Nucleo L432KC", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h index 8b3a8f38b..ce9de3c4d 100644 --- a/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L432KC/mpconfigboard.h @@ -17,7 +17,6 @@ #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) #define MICROPY_HW_HAS_FLASH (1) diff --git a/ports/stm32/boards/NUCLEO_L452RE/board.json b/ports/stm32/boards/NUCLEO_L452RE/board.json new file mode 100644 index 000000000..2ca29ee46 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L452RE/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_l452re.jpg" + ], + "mcu": "stm32l4", + "product": "Nucleo L452RE", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_L476RG/board.json b/ports/stm32/boards/NUCLEO_L476RG/board.json new file mode 100644 index 000000000..82cc8c090 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_L476RG/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_l476rg.jpg" + ], + "mcu": "stm32l4", + "product": "Nucleo L476RG", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_WB55/board.json b/ports/stm32/boards/NUCLEO_WB55/board.json new file mode 100644 index 000000000..eb33995a6 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_WB55/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "nucleo_wb55.jpg" + ], + "mcu": "stm32wb", + "product": "Nucleo WB55", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h index a7473b9d6..19b911a2e 100644 --- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.h @@ -51,9 +51,9 @@ #define MICROPY_HW_USRSW_PRESSED (0) // LEDs -#define MICROPY_HW_LED1 (pin_B1) // red +#define MICROPY_HW_LED1 (pin_B5) // blue #define MICROPY_HW_LED2 (pin_B0) // green -#define MICROPY_HW_LED3 (pin_B5) // blue +#define MICROPY_HW_LED3 (pin_B1) // 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/NUCLEO_WB55/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk index 4cb047c95..dcec788ed 100644 --- a/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_WB55/mpconfigboard.mk @@ -1,7 +1,3 @@ -# By default this board is configured to use mboot with packing (signing and encryption) -# enabled. Mboot must be deployed first. -USE_MBOOT ?= 1 - MCU_SERIES = wb CMSIS_MCU = STM32WB55xx AF_FILE = boards/stm32wb55_af.csv @@ -21,6 +17,3 @@ endif MICROPY_PY_BLUETOOTH = 1 MICROPY_BLUETOOTH_NIMBLE = 1 MICROPY_VFS_LFS2 = 1 - -# Mboot settings -MBOOT_ENABLE_PACKING = 1 diff --git a/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py b/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py index b5f1d0072..4085da90f 100644 --- a/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py +++ b/ports/stm32/boards/NUCLEO_WB55/rfcore_firmware.py @@ -89,7 +89,8 @@ _HCI_KIND_VENDOR_RESPONSE = const(0x11) _OBFUSCATION_KEY = const(0x0573B55AA) # On boards using the internal flash filesystem, this must match the -# `_flash_fs_end` symbol defined by the linker script (boards/stm32wb55xg.ld). +# `_micropy_hw_internal_flash_storage_end` symbol defined by the linker script +# (see eg boards/stm32wb55xg.ld). # We erase everything from here until the start of the secure area (defined by # SFSA) just to ensure that no other fragments of firmware files are left # behind. On boards with external flash, this just needs to ensure that it @@ -537,9 +538,13 @@ def resume(): elif status == 0: log("WS update successful") _write_state(_STATE_WAITING_FOR_WS) - elif result == 0: - # We get a error response with no payload sometimes at the end - # of the update (this is not in AN5185). Re-try the GET_STATE. + elif result in (0, 0xFE): + # We get an error response with no payload sometimes at the end + # of the update (this is not in AN5185). Additionally during + # WS update, newer WS reports (status, result) of (255, 254) + # before eventually reporting the correct state of + # _STATE_INSTALLING_WS once again. In these cases, re-try the + # GET_STATE. # The same thing happens transitioning from WS to FUS mode. # The actual HCI response has no payload, the result=0 comes from # _parse_vendor_response above when len=7. diff --git a/ports/stm32/boards/OLIMEX_E407/board.json b/ports/stm32/boards/OLIMEX_E407/board.json new file mode 100644 index 000000000..c14755c56 --- /dev/null +++ b/ports/stm32/boards/OLIMEX_E407/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "olimex_e407.jpg" + ], + "mcu": "stm32f4", + "product": "E407", + "thumbnail": "", + "url": "", + "vendor": "OLIMEX" +} diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h index 999f97a70..a3b23817d 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h @@ -27,7 +27,7 @@ #define MICROPY_HW_UART3_RTS (pin_D12) #define MICROPY_HW_UART3_CTS (pin_D11) #if MICROPY_HW_HAS_SWITCH == 0 -// NOTE: A0 also connects to the user switch. To use UART4 you should +// NOTE: A0 also connects to the user switch. To use UART4 you should // set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back // of the board near the USER switch). #define MICROPY_HW_UART4_TX (pin_A0) @@ -78,3 +78,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_G14) diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk index b154dcfba..0d3eee83b 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk @@ -4,3 +4,8 @@ AF_FILE = boards/stm32f405_af.csv LD_FILES = boards/stm32f405.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/OLIMEX_E407/pins.csv b/ports/stm32/boards/OLIMEX_E407/pins.csv index 81a9bcb85..cb0a49916 100644 --- a/ports/stm32/boards/OLIMEX_E407/pins.csv +++ b/ports/stm32/boards/OLIMEX_E407/pins.csv @@ -84,3 +84,6 @@ PD15,PD15 PA0,PA0 USB_DM,PA11 USB_DP,PA12 +PG11,PG11 +PG13,PG13 +PG14,PG14 diff --git a/ports/stm32/boards/OLIMEX_H407/README.md b/ports/stm32/boards/OLIMEX_H407/README.md new file mode 100644 index 000000000..458e288e7 --- /dev/null +++ b/ports/stm32/boards/OLIMEX_H407/README.md @@ -0,0 +1,18 @@ +OLIMEX H407 board +================= + +This board definition supports the OLIMEX H407 board: +https://www.olimex.com/Products/ARM/ST/STM32-H407/ + +A REPL is available at the U3BOOT connector with 115200 baud and on the +micro USB socket. + +What works +---------- + +* REPL +* UART +* SD-Card +* Timer +* GPIOs +* USB device on the mini USB socket diff --git a/ports/stm32/boards/OLIMEX_H407/board.json b/ports/stm32/boards/OLIMEX_H407/board.json new file mode 100644 index 000000000..9ecc860dd --- /dev/null +++ b/ports/stm32/boards/OLIMEX_H407/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "olimex_h407.jpg" + ], + "mcu": "stm32f4", + "product": "H407", + "thumbnail": "", + "url": "", + "vendor": "OLIMEX" +} diff --git a/ports/stm32/boards/OLIMEX_H407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_H407/mpconfigboard.h new file mode 100644 index 000000000..813fffeac --- /dev/null +++ b/ports/stm32/boards/OLIMEX_H407/mpconfigboard.h @@ -0,0 +1,81 @@ +#define MICROPY_HW_BOARD_NAME "OLIMEX STM32-H407" +#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) +#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) + +// UART config + +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) + +#define MICROPY_HW_UART3_TX (pin_B10) +#define MICROPY_HW_UART3_RX (pin_B11) + +#define MICROPY_HW_UART3_RTS (pin_D12) +#define MICROPY_HW_UART3_CTS (pin_D11) + +#if MICROPY_HW_HAS_SWITCH == 0 +// NOTE: A0 also connects to the user switch. To use UART4 you should +// set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back +// of the board near the USER switch). +#define MICROPY_HW_UART4_TX (pin_A0) +#define MICROPY_HW_UART4_RX (pin_A1) +#endif + +#define MICROPY_HW_UART6_TX (pin_C6) +#define MICROPY_HW_UART6_RX (pin_C7) + +// REPL mapping +#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) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) + +// SPI buses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#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) + +// CAN buses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_A0) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_C13) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) + +// USB config +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_B13) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_B12) diff --git a/ports/stm32/boards/OLIMEX_H407/mpconfigboard.mk b/ports/stm32/boards/OLIMEX_H407/mpconfigboard.mk new file mode 100644 index 000000000..b154dcfba --- /dev/null +++ b/ports/stm32/boards/OLIMEX_H407/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f4 +CMSIS_MCU = STM32F407xx +AF_FILE = boards/stm32f405_af.csv +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/OLIMEX_H407/pins.csv b/ports/stm32/boards/OLIMEX_H407/pins.csv new file mode 100644 index 000000000..cb0a49916 --- /dev/null +++ b/ports/stm32/boards/OLIMEX_H407/pins.csv @@ -0,0 +1,89 @@ +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PC4,PC4 +PC5,PC5 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +LED_GREEN,PC13 +PC14,PC14 +PC15,PC15 +PH0,PH0 +PH1,PH1 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PA0,PA0 +USB_DM,PA11 +USB_DP,PA12 +PG11,PG11 +PG13,PG13 +PG14,PG14 diff --git a/ports/stm32/boards/OLIMEX_H407/stm32f4xx_hal_conf.h b/ports/stm32/boards/OLIMEX_H407/stm32f4xx_hal_conf.h new file mode 100644 index 000000000..9719157e5 --- /dev/null +++ b/ports/stm32/boards/OLIMEX_H407/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 diff --git a/ports/stm32/boards/PYBD_SF2/board.json b/ports/stm32/boards/PYBD_SF2/board.json new file mode 100644 index 000000000..534a048ff --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/board.json @@ -0,0 +1,21 @@ +{ + "deploy": [ + "deploy.md" + ], + "docs": "", + "features": [], + "id": "PYBD-SF2", + "images": [ + "PYBD_SF2_W4F2.jpg", + "PYBD_SF2_W4F2_top.jpg", + "PYBD_SF2_W4F2_bot.jpg", + "PYBD_SF2_W4F2_ds1.jpg", + "PYBD_SF2_W4F2_ds2.jpg", + "PYBD_SF2_W4F2_ds3.jpg" + ], + "mcu": "stm32f7", + "product": "Pyboard D-series SF2", + "thumbnail": "", + "url": "https://store.micropython.org/product/PYBD-SF2-W4F2", + "vendor": "George Robotics" +} diff --git a/ports/stm32/boards/PYBD_SF2/board.md b/ports/stm32/boards/PYBD_SF2/board.md new file mode 100644 index 000000000..f1074df1a --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/board.md @@ -0,0 +1 @@ +Firmware can be found in the sections below, which is built daily from the ports/stm32/ directory of MicroPython. Check which model you have by the sticker on the top. diff --git a/ports/stm32/boards/PYBD_SF2/deploy.md b/ports/stm32/boards/PYBD_SF2/deploy.md new file mode 100644 index 000000000..afef7b148 --- /dev/null +++ b/ports/stm32/boards/PYBD_SF2/deploy.md @@ -0,0 +1,3 @@ +### Pyboard-D via mboot + +For the pyboard D-series you can enter the mboot DFU bootloader by executing `machine.bootloader()` at the MicroPython REPL. Alternatively, mboot can be entered by holding down the USR button, pressing and releasing the RST button, and continuing to hold down USR until the LED is white (4th in the cycle), then let go of USR while the LED is white. The LED will then flash red once per second to indicate it is in USB DFU mode. You can then program the firmware using a DFU programmer, eg [dfu-util](http://dfu-util.sourceforge.net/) or [pydfu.py](https://github.com/micropython/micropython/blob/master/tools/pydfu.py). diff --git a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h index ed76b3f97..9ac789a83 100644 --- a/ports/stm32/boards/PYBD_SF2/mpconfigboard.h +++ b/ports/stm32/boards/PYBD_SF2/mpconfigboard.h @@ -33,14 +33,12 @@ #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_HW_ENABLE_RF_SWITCH (1) -#define MICROPY_HW_ENABLE_I2S (1) #define MICROPY_BOARD_EARLY_INIT board_early_init #define MICROPY_BOARD_ENTER_STOP board_sleep(1); @@ -183,6 +181,9 @@ extern struct _spi_bdev_t spi_bdev2; #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) #define MICROPY_HW_SDCARD_MOUNT_AT_BOOT (0) +// MM card: the size is hard-coded to support the WBUS-EMMC add-on +#define MICROPY_HW_MMCARD_LOG_BLOCK_NBR (7469056 + 2048) + // USB config #define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_HS (1) diff --git a/ports/stm32/boards/PYBD_SF3/board.json b/ports/stm32/boards/PYBD_SF3/board.json new file mode 100644 index 000000000..3e4731b3d --- /dev/null +++ b/ports/stm32/boards/PYBD_SF3/board.json @@ -0,0 +1,21 @@ +{ + "deploy": [ + "../PYBD_SF2/deploy.md" + ], + "docs": "", + "features": [], + "id": "PYBD-SF3", + "images": [ + "PYBD_SF3_W4F2.jpg", + "PYBD_SF3_W4F2_top.jpg", + "PYBD_SF2_W4F2_bot.jpg", + "PYBD_SF3_W4F2_ds1.jpg", + "PYBD_SF3_W4F2_ds2.jpg", + "PYBD_SF3_W4F2_ds3.jpg" + ], + "mcu": "stm32f7", + "product": "Pyboard D-series SF3", + "thumbnail": "", + "url": "https://store.micropython.org/product/PYBD-SF3-W4F2", + "vendor": "George Robotics" +} diff --git a/ports/stm32/boards/PYBD_SF3/board.md b/ports/stm32/boards/PYBD_SF3/board.md new file mode 100644 index 000000000..f1074df1a --- /dev/null +++ b/ports/stm32/boards/PYBD_SF3/board.md @@ -0,0 +1 @@ +Firmware can be found in the sections below, which is built daily from the ports/stm32/ directory of MicroPython. Check which model you have by the sticker on the top. diff --git a/ports/stm32/boards/PYBD_SF6/board.json b/ports/stm32/boards/PYBD_SF6/board.json new file mode 100644 index 000000000..3e689d69b --- /dev/null +++ b/ports/stm32/boards/PYBD_SF6/board.json @@ -0,0 +1,24 @@ +{ + "deploy": [ + "../PYBD_SF2/deploy.md" + ], + "docs": "", + "features": [ + "WiFi", + "BLE" + ], + "id": "PYBD-SF6", + "images": [ + "PYBD_SF6_W4F2.jpg", + "PYBD_SF6_W4F2_top.jpg", + "PYBD_SF2_W4F2_bot.jpg", + "PYBD_SF6_W4F2_ds1.jpg", + "PYBD_SF6_W4F2_ds2.jpg", + "PYBD_SF6_W4F2_ds3.jpg" + ], + "mcu": "stm32f7", + "product": "Pyboard D-series SF6", + "thumbnail": "", + "url": "https://store.micropython.org/product/PYBD-SF6-W4F2", + "vendor": "George Robotics" +} diff --git a/ports/stm32/boards/PYBD_SF6/board.md b/ports/stm32/boards/PYBD_SF6/board.md new file mode 100644 index 000000000..f1074df1a --- /dev/null +++ b/ports/stm32/boards/PYBD_SF6/board.md @@ -0,0 +1 @@ +Firmware can be found in the sections below, which is built daily from the ports/stm32/ directory of MicroPython. Check which model you have by the sticker on the top. diff --git a/ports/stm32/boards/PYBLITEV10/board.json b/ports/stm32/boards/PYBLITEV10/board.json new file mode 100644 index 000000000..ce98ba7de --- /dev/null +++ b/ports/stm32/boards/PYBLITEV10/board.json @@ -0,0 +1,24 @@ +{ + "deploy": [ + "../PYBV10/deploy.md" + ], + "docs": "", + "features": [], + "id": "pyblitev10", + "images": [ + "PYBLITEv1_0.jpg", + "PYBLITEv1_0-B.jpg", + "PYBLITEv1_0-C.jpg" + ], + "mcu": "stm32f4", + "product": "Pyboard Lite v1.0", + "thumbnail": "", + "url": "https://store.micropython.org/product/PYBLITEv1.0", + "variants": { + "dp": "Double-precision float", + "dp-thread": "Double precision float + Threads", + "network": "Wiznet 5200 Driver", + "thread": "Threading" + }, + "vendor": "George Robotics" +} diff --git a/ports/stm32/boards/PYBLITEV10/board.md b/ports/stm32/boards/PYBLITEV10/board.md new file mode 100644 index 000000000..1511ffcf5 --- /dev/null +++ b/ports/stm32/boards/PYBLITEV10/board.md @@ -0,0 +1 @@ +The "standard" build is listed first and is the default firmware that the pyboards are shipped with. Use this firmware if you are uncertain. The "double FP" builds use double-precision floating point instead of the standard single precision. The "threading" builds contain the \_thread module and allow multithreading. The "network" builds have network drivers for CC3000 and WIZ820io included. All these different firmware are completely interchangeable and you can freely change from one to the other without losing the filesystem on your pyboard. diff --git a/ports/stm32/boards/PYBV10/board.json b/ports/stm32/boards/PYBV10/board.json new file mode 100644 index 000000000..2907b8fc4 --- /dev/null +++ b/ports/stm32/boards/PYBV10/board.json @@ -0,0 +1,22 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "id": "pybv10", + "images": [ + "PYBv1_0-C.jpg" + ], + "mcu": "stm32f4", + "product": "Pyboard v1.0", + "thumbnail": "", + "url": "", + "variants": { + "dp": "Double-precision float", + "dp-thread": "Double precision float + Threads", + "network": "Wiznet 5200 Driver", + "thread": "Threading" + }, + "vendor": "George Robotics" +} diff --git a/ports/stm32/boards/PYBV10/board.md b/ports/stm32/boards/PYBV10/board.md new file mode 100644 index 000000000..1511ffcf5 --- /dev/null +++ b/ports/stm32/boards/PYBV10/board.md @@ -0,0 +1 @@ +The "standard" build is listed first and is the default firmware that the pyboards are shipped with. Use this firmware if you are uncertain. The "double FP" builds use double-precision floating point instead of the standard single precision. The "threading" builds contain the \_thread module and allow multithreading. The "network" builds have network drivers for CC3000 and WIZ820io included. All these different firmware are completely interchangeable and you can freely change from one to the other without losing the filesystem on your pyboard. diff --git a/ports/stm32/boards/PYBV10/deploy.md b/ports/stm32/boards/PYBV10/deploy.md new file mode 100644 index 000000000..d7c21999e --- /dev/null +++ b/ports/stm32/boards/PYBV10/deploy.md @@ -0,0 +1,6 @@ +### Pyboard v1.x via DFU + +One you have downloaded the appropriate DFU file it can be flashed directly to your pyboard +using a DFU programmer. You can enter the DFU bootloader on the pyboard by executing `machine.bootloader()` at the MicroPython REPL. + +Alternatively, connect 3V3 with BOOT0 and reset the board. For information about DFU programming on Windows see [this PDF](http://micropython.org/resources/Micro-Python-Windows-setup.pdf). For Linux and Mac see [here](https://github.com/micropython/micropython/wiki/Pyboard-Firmware-Update). diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h index 50ef3ae26..6219862be 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBV10/mpconfigboard.h @@ -11,7 +11,6 @@ #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SDCARD (1) -#define MICROPY_HW_ENABLE_I2S (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/PYBV11/board.json b/ports/stm32/boards/PYBV11/board.json new file mode 100644 index 000000000..fe59a7b16 --- /dev/null +++ b/ports/stm32/boards/PYBV11/board.json @@ -0,0 +1,24 @@ +{ + "deploy": [ + "../PYBV10/deploy.md" + ], + "docs": "", + "features": [], + "id": "pybv11", + "images": [ + "PYBv1_1.jpg", + "PYBv1_1-C.jpg", + "PYBv1_1-E.jpg" + ], + "mcu": "stm32f4", + "product": "Pyboard v1.1", + "thumbnail": "", + "url": "https://store.micropython.org/product/PYBv1.1", + "variants": { + "dp": "Double-precision float", + "dp-thread": "Double precision float + Threads", + "network": "Wiznet 5200 Driver", + "thread": "Threading" + }, + "vendor": "George Robotics" +} diff --git a/ports/stm32/boards/PYBV11/board.md b/ports/stm32/boards/PYBV11/board.md new file mode 100644 index 000000000..1511ffcf5 --- /dev/null +++ b/ports/stm32/boards/PYBV11/board.md @@ -0,0 +1 @@ +The "standard" build is listed first and is the default firmware that the pyboards are shipped with. Use this firmware if you are uncertain. The "double FP" builds use double-precision floating point instead of the standard single precision. The "threading" builds contain the \_thread module and allow multithreading. The "network" builds have network drivers for CC3000 and WIZ820io included. All these different firmware are completely interchangeable and you can freely change from one to the other without losing the filesystem on your pyboard. diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h index aec83d134..c8f660c8f 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.h +++ b/ports/stm32/boards/PYBV11/mpconfigboard.h @@ -11,7 +11,6 @@ #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SDCARD (1) -#define MICROPY_HW_ENABLE_I2S (1) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) diff --git a/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json new file mode 100644 index 000000000..0bd3573d6 --- /dev/null +++ b/ports/stm32/boards/SPARKFUN_MICROMOD_STM32/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "sparkfun_micromod_stm32.jpg" + ], + "mcu": "stm32f4", + "product": "Micromod STM32", + "thumbnail": "", + "url": "", + "vendor": "Sparkfun" +} diff --git a/ports/stm32/boards/STM32F411DISC/board.json b/ports/stm32/boards/STM32F411DISC/board.json new file mode 100644 index 000000000..97761ddbf --- /dev/null +++ b/ports/stm32/boards/STM32F411DISC/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "stm32f411disc.jpg" + ], + "mcu": "stm32f4", + "product": "Discovery F411", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/STM32F429DISC/board.json b/ports/stm32/boards/STM32F429DISC/board.json new file mode 100644 index 000000000..4c7ee395f --- /dev/null +++ b/ports/stm32/boards/STM32F429DISC/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "stm32f429disc.jpg" + ], + "mcu": "stm32f4", + "product": "Discovery F429", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h index cfd9ef9d0..bae6ae255 100644 --- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h @@ -6,6 +6,7 @@ #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) diff --git a/ports/stm32/boards/STM32F439/board.json b/ports/stm32/boards/STM32F439/board.json new file mode 100644 index 000000000..140c3474c --- /dev/null +++ b/ports/stm32/boards/STM32F439/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "stm32f439.jpg" + ], + "mcu": "stm32f4", + "product": "STM32F439", + "thumbnail": "", + "url": "", + "vendor": "" +} diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.h b/ports/stm32/boards/STM32F439/mpconfigboard.h index 702ef265b..917ea8948 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.h +++ b/ports/stm32/boards/STM32F439/mpconfigboard.h @@ -6,6 +6,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_SDCARD (1) // works with no SD card too // SD card detect switch diff --git a/ports/stm32/boards/STM32F4DISC/board.json b/ports/stm32/boards/STM32F4DISC/board.json new file mode 100644 index 000000000..64a8faba3 --- /dev/null +++ b/ports/stm32/boards/STM32F4DISC/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "stm32f4disc.jpg" + ], + "mcu": "stm32f4", + "product": "Discovery F4", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h index dbe52e6b1..d4ecde17d 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h @@ -7,6 +7,7 @@ #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_ENABLE_SERVO (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -31,7 +32,7 @@ #define MICROPY_HW_UART3_RTS (pin_D12) #define MICROPY_HW_UART3_CTS (pin_D11) #if MICROPY_HW_HAS_SWITCH == 0 -// NOTE: A0 also connects to the user switch. To use UART4 you should +// NOTE: A0 also connects to the user switch. To use UART4 you should // set MICROPY_HW_HAS_SWITCH to 0, and also remove SB20 (on the back // of the board near the USER switch). #define MICROPY_HW_UART4_TX (pin_A0) diff --git a/ports/stm32/boards/STM32F769DISC/board.json b/ports/stm32/boards/STM32F769DISC/board.json new file mode 100644 index 000000000..ce38ec788 --- /dev/null +++ b/ports/stm32/boards/STM32F769DISC/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "stm32f769disc.jpg" + ], + "mcu": "stm32f7", + "product": "Discovery F769", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index 87cefb501..8728d1b37 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -10,6 +10,7 @@ #define MICROPY_HW_ENABLE_RNG (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) #define MICROPY_BOARD_EARLY_INIT board_early_init @@ -85,7 +86,7 @@ extern struct _spi_bdev_t spi_bdev; // LEDs #define MICROPY_HW_LED1 (pin_J13) // red -#define MICROPY_HW_LED2 (pin_J5) // green +#define MICROPY_HW_LED2 (pin_J5) // green #define MICROPY_HW_LED3 (pin_A12) // 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/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 5d3d11a79..dfee1a7ac 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -1,6 +1,3 @@ -# By default this board is configured to use mboot which must be deployed first -USE_MBOOT ?= 1 - # 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 diff --git a/ports/stm32/boards/STM32F7DISC/board.json b/ports/stm32/boards/STM32F7DISC/board.json new file mode 100644 index 000000000..1eaae6b68 --- /dev/null +++ b/ports/stm32/boards/STM32F7DISC/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "stm32f7disc.jpg" + ], + "mcu": "stm32f7", + "product": "Discovery F7", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/STM32H7B3I_DK/board.json b/ports/stm32/boards/STM32H7B3I_DK/board.json new file mode 100644 index 000000000..a1ab50c0d --- /dev/null +++ b/ports/stm32/boards/STM32H7B3I_DK/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "stm32h7b3i_dk.jpg" + ], + "mcu": "stm32h7", + "product": "Discovery Kit H7", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.h b/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.h new file mode 100644 index 000000000..02f5fcac2 --- /dev/null +++ b/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.h @@ -0,0 +1,86 @@ +#define MICROPY_HW_BOARD_NAME "STM32H7B3I-DK" +#define MICROPY_HW_MCU_NAME "STM32H7B3LIH6Q" + +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_RNG (1) +#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 (0) + +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) + +// The board has a 24MHz HSE, the following gives 280MHz CPU speed +#define MICROPY_HW_CLK_PLLM (12) +#define MICROPY_HW_CLK_PLLN (280) +#define MICROPY_HW_CLK_PLLP (2) +#define MICROPY_HW_CLK_PLLQ (2) +#define MICROPY_HW_CLK_PLLR (2) + +// The USB clock is set using PLL3 (48Mhz usb clock) +#define MICROPY_HW_CLK_PLL3M (12) +#define MICROPY_HW_CLK_PLL3N (192) +#define MICROPY_HW_CLK_PLL3P (17) +#define MICROPY_HW_CLK_PLL3Q (8) +#define MICROPY_HW_CLK_PLL3R (2) + +// 6 wait states when running at 280MHz (VOS0 range) +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_6 + +#if 0 +// 512MBit external OSPI flash, used for either the filesystem or XIP memory mapped +#define MICROPY_HW_OSPIFLASH_SIZE_BITS_LOG2 (29) +#define MICROPY_HW_OSPIFLASH_CS (pin_G6) +#define MICROPY_HW_OSPIFLASH_CLK (pin_B2) +#define MICROPY_HW_OSPIFLASH_DQS (pin_C5) +#define MICROPY_HW_OSPIFLASH_IO0 (pin_P8) +#define MICROPY_HW_OSPIFLASH_IO1 (pin_F9) +#define MICROPY_HW_OSPIFLASH_IO2 (pin_F7) +#define MICROPY_HW_OSPIFLASH_IO3 (pin_F6) +#define MICROPY_HW_OSPIFLASH_IO4 (pin_C1) +#define MICROPY_HW_OSPIFLASH_IO5 (pin_H3) +#define MICROPY_HW_OSPIFLASH_IO6 (pin_D6) +#define MICROPY_HW_OSPIFLASH_IO7 (pin_G14) +#endif + +// UART buses +#define MICROPY_HW_UART1_TX (pin_A9) +#define MICROPY_HW_UART1_RX (pin_A10) +#define MICROPY_HW_UART4_TX (pin_H13) // Arduino Connector CN11-Pin1 +#define MICROPY_HW_UART4_RX (pin_H14) // Arduino Connector CN11-Pin2 +#define MICROPY_HW_UART_REPL PYB_UART_1 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// 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_G11) // red +#define MICROPY_HW_LED2 (pin_G2) // blue +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) + +// USB config +#define MICROPY_HW_USB_FS (0) +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) +#define MICROPY_HW_USB_CDC_NUM (2) +#define MICROPY_HW_USB_MSC (0) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_I8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) + +#define MICROPY_HW_SDMMC_D0 (pin_C8) +#define MICROPY_HW_SDMMC_D1 (pin_C9) +#define MICROPY_HW_SDMMC_D2 (pin_C10) +#define MICROPY_HW_SDMMC_D3 (pin_C11) +#define MICROPY_HW_SDMMC_CK (pin_C12) +#define MICROPY_HW_SDMMC_CMD (pin_D2) diff --git a/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.mk b/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.mk new file mode 100644 index 000000000..380ade8d0 --- /dev/null +++ b/ports/stm32/boards/STM32H7B3I_DK/mpconfigboard.mk @@ -0,0 +1,18 @@ +USE_MBOOT ?= 0 + +# MCU settings +MCU_SERIES = h7 +CMSIS_MCU = STM32H7B3xxQ +MICROPY_FLOAT_IMPL = double +AF_FILE = boards/stm32h7b3_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/stm32h7b3.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08040000 +endif diff --git a/ports/stm32/boards/STM32H7B3I_DK/pins.csv b/ports/stm32/boards/STM32H7B3I_DK/pins.csv new file mode 100644 index 000000000..e005e38af --- /dev/null +++ b/ports/stm32/boards/STM32H7B3I_DK/pins.csv @@ -0,0 +1,191 @@ +,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 +,PD0 +,PD1 +,PD2 +,PD3 +,PD4 +,PD5 +,PD6 +,PD7 +,PD8 +,PD9 +,PD10 +,PD11 +,PD12 +,PD13 +,PD14 +,PD15 +,PE0 +,PE1 +,PE2 +,PE3 +,PE4 +,PE5 +,PE6 +,PE7 +,PE8 +,PE9 +,PE10 +,PE11 +,PE12 +,PE13 +,PE14 +,PE15 +,PF0 +,PF1 +,PF2 +,PF3 +,PF4 +,PF5 +,PF6 +,PF7 +,PF8 +,PF9 +,PF10 +,PF11 +,PF12 +,PF13 +,PF14 +,PF15 +,PG0 +,PG1 +,PG2 +,PG3 +,PG4 +,PG5 +,PG6 +,PG7 +,PG8 +,PG9 +,PG10 +,PG11 +,PG12 +,PG13 +,PG14 +,PG15 +,PH0 +,PH1 +,PH2 +,PH3 +,PH4 +,PH5 +,PH6 +,PH7 +,PH8 +,PH9 +,PH10 +,PH11 +,PH12 +,PH13 +,PH14 +,PH15 +,PI0 +,PI1 +,PI2 +,PI3 +,PI4 +,PI5 +,PI6 +,PI7 +,PI8 +,PI9 +,PI10 +,PI11 +,PI12 +,PI13 +,PI14 +,PI15 +DAC1,PA4 +DAC2,PA5 +LED1,G11 +LED2,G2 +SW,PC13 +I2C1_SDA,PB9 +I2C1_SCL,PB8 +I2C2_SDA,PF0 +I2C2_SCL,PF1 +I2C4_SCL,PF14 +I2C4_SDA,PF15 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD_SW,PG2 +OTG_FS_POWER,PG6 +OTG_FS_OVER_CURRENT,PG7 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +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 diff --git a/ports/stm32/boards/STM32H7B3I_DK/stm32h7xx_hal_conf.h b/ports/stm32/boards/STM32H7B3I_DK/stm32h7xx_hal_conf.h new file mode 100644 index 000000000..70c3246a8 --- /dev/null +++ b/ports/stm32/boards/STM32H7B3I_DK/stm32h7xx_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_STM32H7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H + +#include "boards/stm32h7xx_hal_conf_base.h" + +// Oscillator values in Hz +#define HSE_VALUE (24000000) +#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_STM32H7XX_HAL_CONF_H diff --git a/ports/stm32/boards/STM32L476DISC/board.json b/ports/stm32/boards/STM32L476DISC/board.json new file mode 100644 index 000000000..49d1060ee --- /dev/null +++ b/ports/stm32/boards/STM32L476DISC/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "stm32l476disc.jpg" + ], + "mcu": "stm32l4", + "product": "Discovery L476", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/STM32L496GDISC/board.json b/ports/stm32/boards/STM32L496GDISC/board.json new file mode 100644 index 000000000..b152948c1 --- /dev/null +++ b/ports/stm32/boards/STM32L496GDISC/board.json @@ -0,0 +1,13 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [], + "mcu": "stm32l4", + "product": "Discovery L496G", + "thumbnail": "", + "url": "", + "vendor": "ST Microelectronics" +} diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h index d4d78454a..944d6ecd5 100644 --- a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h @@ -4,7 +4,6 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_USB (1) // MSI is used and is 4MHz, diff --git a/ports/stm32/boards/USBDONGLE_WB55/board.json b/ports/stm32/boards/USBDONGLE_WB55/board.json new file mode 100644 index 000000000..858e94d10 --- /dev/null +++ b/ports/stm32/boards/USBDONGLE_WB55/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "usbdongle_wb55.jpg" + ], + "mcu": "stm32wb", + "product": "USBDONGLE_WB55", + "thumbnail": "", + "url": "", + "vendor": "" +} diff --git a/ports/stm32/boards/VCC_GND_F407VE/board.json b/ports/stm32/boards/VCC_GND_F407VE/board.json new file mode 100644 index 000000000..11e12ff97 --- /dev/null +++ b/ports/stm32/boards/VCC_GND_F407VE/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "STM32F407VET6.jpg" + ], + "mcu": "stm32f4", + "product": "F407VE", + "thumbnail": "", + "url": "http://vcc-gnd.com/", + "vendor": "VCC-GND Studio" +} diff --git a/ports/stm32/boards/VCC_GND_F407ZG/board.json b/ports/stm32/boards/VCC_GND_F407ZG/board.json new file mode 100644 index 000000000..bf0352b2d --- /dev/null +++ b/ports/stm32/boards/VCC_GND_F407ZG/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "STM32F407ZGT6.jpg" + ], + "mcu": "stm32f4", + "product": "F407ZG", + "thumbnail": "", + "url": "http://vcc-gnd.com/", + "vendor": "VCC-GND Studio" +} diff --git a/ports/stm32/boards/VCC_GND_H743VI/board.json b/ports/stm32/boards/VCC_GND_H743VI/board.json new file mode 100644 index 000000000..f7539ac9f --- /dev/null +++ b/ports/stm32/boards/VCC_GND_H743VI/board.json @@ -0,0 +1,15 @@ +{ + "deploy": [ + "../deploy.md" + ], + "docs": "", + "features": [], + "images": [ + "STM32H743VIT6.jpg" + ], + "mcu": "stm32h7", + "product": "H743VI", + "thumbnail": "", + "url": "http://vcc-gnd.com/", + "vendor": "VCC-GND Studio" +} diff --git a/ports/stm32/boards/VCC_GND_H743VI/board_init.c b/ports/stm32/boards/VCC_GND_H743VI/board_init.c new file mode 100644 index 000000000..53b685ff9 --- /dev/null +++ b/ports/stm32/boards/VCC_GND_H743VI/board_init.c @@ -0,0 +1,9 @@ +#include "py/mphal.h" + +void VCC_GND_STM32H743VI_board_early_init(void) { + // set SPI and QSPI flashes CS pin high + mp_hal_pin_output(pin_B10); + mp_hal_pin_write(pin_B10, 1); + mp_hal_pin_output(pin_B12); + mp_hal_pin_write(pin_B12, 1); +} diff --git a/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.h b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.h new file mode 100644 index 000000000..9ef5490fd --- /dev/null +++ b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.h @@ -0,0 +1,103 @@ +/* This file is part of the MicroPython project, http://micropython.org/ + * MIT License; Copyright (c) 2021 Damien P. George + */ + +// STM32H743VIT6 H7 core board by VCC-GND Studio +// http://vcc-gnd.com/ +// https://item.taobao.com/item.htm?ft=t&id=614466740679 +// https://www.aliexpress.com/wholesale?SearchText=STM32H743VIT6 + +#define MICROPY_HW_BOARD_NAME "VCC-GND STM32H743VI" +#define MICROPY_HW_MCU_NAME "STM32H743VI" +#define MICROPY_HW_FLASH_FS_LABEL "VCCGNDH743VI" + +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_RNG (1) +#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_BOARD_EARLY_INIT VCC_GND_STM32H743VI_board_early_init + +// The board has an 25MHz HSE, the following gives 480MHz CPU speed +#define MICROPY_HW_CLK_PLLM (5) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (2) +#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_PLLR (2) + +// The USB clock is set using PLL3 +#define MICROPY_HW_CLK_PLL3M (5) +#define MICROPY_HW_CLK_PLL3N (48) +#define MICROPY_HW_CLK_PLL3P (2) +#define MICROPY_HW_CLK_PLL3Q (5) +#define MICROPY_HW_CLK_PLL3R (2) + +// 5 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5 + +// 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_UART8_TX (pin_E1) +#define MICROPY_HW_UART8_RX (pin_E0) + +// I2C buses +#define MICROPY_HW_I2C1_SCL (pin_B6) +#define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) +#define MICROPY_HW_I2C3_SCL (pin_A8) +#define MICROPY_HW_I2C3_SDA (pin_C9) + +// SPI buses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#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) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_B3) +#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_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_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// FDCAN bus +#define MICROPY_HW_CAN1_NAME "FDCAN1" +#define MICROPY_HW_CAN1_TX (pin_D1) +#define MICROPY_HW_CAN1_RX (pin_D0) + +// 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) + +void VCC_GND_STM32H743VI_board_early_init(void); diff --git a/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk new file mode 100644 index 000000000..886082948 --- /dev/null +++ b/ports/stm32/boards/VCC_GND_H743VI/mpconfigboard.mk @@ -0,0 +1,20 @@ +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 everything goes after the bootloader +LD_FILES = boards/stm32h743.ld boards/common_bl.ld +TEXT0_ADDR = 0x08020000 +else +# When not using Mboot everything goes at the start of flash +LD_FILES = boards/stm32h743.ld boards/common_basic.ld +TEXT0_ADDR = 0x08000000 +endif + +# MicroPython settings +MICROPY_VFS_LFS2 = 1 diff --git a/ports/stm32/boards/VCC_GND_H743VI/pins.csv b/ports/stm32/boards/VCC_GND_H743VI/pins.csv new file mode 100644 index 000000000..6668a92db --- /dev/null +++ b/ports/stm32/boards/VCC_GND_H743VI/pins.csv @@ -0,0 +1,80 @@ +A0,PA0 +A1,PA1 +A2,PA2 +A3,PA3 +A4,PA4 +A5,PA5 +A6,PA6 +A7,PA7 +A8,PA8 +A9,PA9 +A10,PA10 +A11,PA11 +A12,PA12 +A13,PA13 +A14,PA14 +A15,PA15 +B0,PB0 +B1,PB1 +B2,PB2 +B3,PB3 +B4,PB4 +B5,PB5 +B6,PB6 +B7,PB7 +B8,PB8 +B9,PB9 +B10,PB10 +B11,PB11 +B12,PB12 +B13,PB13 +B14,PB14 +B15,PB15 +C0,PC0 +C1,PC1 +C2,PC2 +C3,PC3 +C4,PC4 +C5,PC5 +C6,PC6 +C7,PC7 +C8,PC8 +C9,PC9 +C10,PC10 +C11,PC11 +C12,PC12 +C13,PC13 +C14,PC14 +C15,PC15 +D0,PD0 +D1,PD1 +D2,PD2 +D3,PD3 +D4,PD4 +D5,PD5 +D6,PD6 +D7,PD7 +D8,PD8 +D9,PD9 +D10,PD10 +D11,PD11 +D12,PD12 +D13,PD13 +D14,PD14 +D15,PD15 +E0,PE0 +E1,PE1 +E2,PE2 +E3,PE3 +E4,PE4 +E5,PE5 +E6,PE6 +E7,PE7 +E8,PE8 +E9,PE9 +E10,PE10 +E11,PE11 +E12,PE12 +E13,PE13 +E14,PE14 +E15,PE15 diff --git a/ports/stm32/boards/VCC_GND_H743VI/stm32h7xx_hal_conf.h b/ports/stm32/boards/VCC_GND_H743VI/stm32h7xx_hal_conf.h new file mode 100644 index 000000000..c4d148b0b --- /dev/null +++ b/ports/stm32/boards/VCC_GND_H743VI/stm32h7xx_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_STM32H7XX_HAL_CONF_H +#define MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H + +#include "boards/stm32h7xx_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 (5000) +#define LSE_STARTUP_TIMEOUT (5000) + +#endif // MICROPY_INCLUDED_STM32H7XX_HAL_CONF_H diff --git a/ports/stm32/boards/deploy.md b/ports/stm32/boards/deploy.md new file mode 100644 index 000000000..db2b4ef3a --- /dev/null +++ b/ports/stm32/boards/deploy.md @@ -0,0 +1,31 @@ +### STM32 via ST-Link + +Nucleo and Discovery boards typically include a built-in ST-Link programmer. + +A `.bin` or `.hex` file can be flashed using [st-flash](https://github.com/stlink-org/stlink). + +```bash +# Optional erase to clear existing filesystem. +st-flash erase + +# Flash .bin +st-flash write firmware.bin 0x08000000 +# or, flash .hex +st-flash --format ihex write firmware.hex +``` + +A `.hex` file can be flashed using [STM32 Cube Programmer](https://www.st.com/en/development-tools/stm32cubeprog.html). + +```bash +STM32_Programmer.sh -c port=SWD -d firmware.hex -hardRst +``` + +### STM32 via DFU + +Boards with USB support can also be programmed via the ST DFU bootloader, using e.g. [dfu-util](http://dfu-util.sourceforge.net/) or [pydfu.py](https://github.com/micropython/micropython/blob/master/tools/pydfu.py). + +To enter the bootloader the `BOOT0` pin can be connected to `VCC` during reset, or you can use `machine.bootloader()` from the MicroPython REPL. + +```bash +dfu-util --alt 0 -D firmware.dfu +``` diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py index d898832f0..14c9e9109 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -1,5 +1,50 @@ #!/usr/bin/env python -"""Creates the pin file for the STM32F4xx.""" + +""" +Generates pin source files based on an MCU alternate-function definition (eg +stm32f405_af.csv) and a board-specific pin definition file, pins.csv. + +The pins.csv file can contain empty lines, comments (a line beginning with "#") +or pin definition lines. Pin definition lines must be of the form: + + board,cpu + +Where "board" is the user-facing name of the pin as specified by the particular +board layout and markings, and "cpu" is the corresponding name of the CPU/MCU +pin. + +The "board" entry may be absent if the CPU pin has no additional name, and both +entries may start with "-" to hide them from the corresponding Python dict of +pins, and hence hide them from the user (but they are still accessible in C). + +For example, take the following pins.csv file: + + X1,PA0 + -X2,PA1 + X3,-PA2 + -X4,-PA3 + ,PA4 + ,-PA5 + +The first row here configures: +- The CPU pin PA0 is labelled X1. +- The Python user can access both by the names Pin("X1") and Pin("A0"). +- The Python user can access both by the members Pin.board.X1 and Pin.cpu.A0. +- In C code they are available as pyb_pin_X1 and pin_A0. + +Prefixing the names with "-" hides them from the user. The following table +summarises the various possibilities: + + pins.csv entry | board name | cpu name | C board name | C cpu name + ---------------+------------+----------+--------------+----------- + X1,PA0 "X1" "A0" pyb_pin_X1 pin_A0 + -X2,PA1 - "A1" pyb_pin_X2 pin_A1 + X3,-PA2 "X3" - pyb_pin_X3 pin_A2 + -X4,-PA3 - - pyb_pin_X4 pin_A3 + ,PA4 - "A4" - pin_A4 + ,-PA5 - - - pin_A5 + +""" from __future__ import print_function @@ -273,6 +318,9 @@ class NamedPin(object): self._name = name self._pin = pin + def set_hidden(self, value): + self._is_hidden = value + def is_hidden(self): return self._is_hidden @@ -293,7 +341,7 @@ class Pins(object): for named_pin in self.cpu_pins: pin = named_pin.pin() if pin.port == port_num and pin.pin == pin_num: - return pin + return named_pin def parse_af_file(self, filename, pinname_col, af_col): with open(filename, "r") as csvfile: @@ -315,12 +363,25 @@ class Pins(object): with open(filename, "r") as csvfile: rows = csv.reader(csvfile) for row in rows: + if len(row) == 0 or row[0].startswith("#"): + # Skip empty lines, and lines starting with "#" + continue + if len(row) != 2: + raise ValueError("Expecting two entries in a row") + + cpu_pin_name = row[1] + cpu_pin_hidden = False + if cpu_pin_name.startswith("-"): + cpu_pin_name = cpu_pin_name[1:] + cpu_pin_hidden = True try: - (port_num, pin_num) = parse_port_pin(row[1]) + (port_num, pin_num) = parse_port_pin(cpu_pin_name) except: continue - pin = self.find_pin(port_num, pin_num) - if pin: + named_pin = self.find_pin(port_num, pin_num) + if named_pin: + named_pin.set_hidden(cpu_pin_hidden) + pin = named_pin.pin() pin.set_is_board_pin() if row[0]: # Only add board pins that have a name self.board_pins.append(NamedPin(row[0], pin)) @@ -365,16 +426,19 @@ class Pins(object): adc_pins[pin.adc_channel] = pin if adc_pins: table_size = max(adc_pins) + 1 - self.adc_table_size[adc_num] = table_size - print("") - print("const pin_obj_t * const pin_adc{:d}[{:d}] = {{".format(adc_num, table_size)) - for channel in range(table_size): - if channel in adc_pins: - obj = "&pin_{:s}_obj".format(adc_pins[channel].cpu_pin_name()) - else: - obj = "NULL" - print(" [{:d}] = {},".format(channel, obj)) - print("};") + else: + # If ADCx pins are hidden, print an empty table to prevent linker errors. + table_size = 0 + self.adc_table_size[adc_num] = table_size + print("") + print("const pin_obj_t * const pin_adc{:d}[{:d}] = {{".format(adc_num, table_size)) + for channel in range(table_size): + if channel in adc_pins: + obj = "&pin_{:s}_obj".format(adc_pins[channel].cpu_pin_name()) + else: + obj = "NULL" + print(" [{:d}] = {},".format(channel, obj)) + print("};") def print_header(self, hdr_filename, obj_decls): with open(hdr_filename, "wt") as hdr_file: @@ -443,7 +507,7 @@ class Pins(object): with open(af_defs_filename, "wt") as af_defs_file: STATIC_AF_TOKENS = {} - for named_pin in self.board_pins: + for named_pin in self.cpu_pins: for af in named_pin.pin().alt_fn: func = "%s%d" % (af.func, af.fn_num) if af.fn_num else af.func pin_type = (af.pin_type or "NULL").split("(")[0] diff --git a/ports/stm32/boards/stm32f091_af.csv b/ports/stm32/boards/stm32f091_af.csv index 38e134f8a..8074fd22b 100644 --- a/ports/stm32/boards/stm32f091_af.csv +++ b/ports/stm32/boards/stm32f091_af.csv @@ -87,3 +87,4 @@ PortF,PF3,EVENTOUT,USART7_RX,USART6_CK/USART6_RTS,,,,,,,,,,,,,, PortF,PF6,,,,,,,,,,,,,,,,, PortF,PF9,TIM15_CH1,USART6_TX,,,,,,,,,,,,,,, PortF,PF10,TIM15_CH2,USART6_RX,,,,,,,,,,,,,,, +PortF,PF11,,,,,,,,,,,,,,,,, diff --git a/ports/stm32/boards/stm32f413xg.ld b/ports/stm32/boards/stm32f413xg.ld index 96d6dc5fb..cecfcaa88 100644 --- a/ports/stm32/boards/stm32f413xg.ld +++ b/ports/stm32/boards/stm32f413xg.ld @@ -3,15 +3,14 @@ */ /* 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_FS2 (rx) : ORIGIN = 0x08040000, LENGTH = 64K /* 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 + SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 64K /* used for filesystem cache */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K } @@ -29,3 +28,11 @@ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ _heap_end = _sstack; + +/* Filesystem cache in RAM, and storage in flash */ +_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(SRAM2); +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2); +_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2); diff --git a/ports/stm32/boards/stm32f413xh.ld b/ports/stm32/boards/stm32f413xh.ld index 0b28730de..0846b5c80 100644 --- a/ports/stm32/boards/stm32f413xh.ld +++ b/ports/stm32/boards/stm32f413xh.ld @@ -3,15 +3,14 @@ */ /* 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_FS2 (rx) : ORIGIN = 0x08040000, LENGTH = 64K /* 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 + SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 64K /* used for filesystem cache */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K } @@ -29,3 +28,11 @@ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ _heap_end = _sstack; + +/* Filesystem cache in RAM, and storage in flash */ +_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(SRAM2); +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2); +_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2); diff --git a/ports/stm32/boards/stm32f427xi.ld b/ports/stm32/boards/stm32f427xi.ld new file mode 100644 index 000000000..1197848af --- /dev/null +++ b/ports/stm32/boards/stm32f427xi.ld @@ -0,0 +1,28 @@ +/* + GNU linker script for STM32F427xI +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* entire flash */ + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0, 16 KiB */ + FLASH_FS (rx) : ORIGIN = 0x08004000, LENGTH = 112K /* sectors 1-4: 3*16K+64K */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 5-11 are 128K */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K +} + +/* 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 */ + +/* 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 = _sstack; diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld index e847646b3..64195368c 100644 --- a/ports/stm32/boards/stm32f439.ld +++ b/ports/stm32/boards/stm32f439.ld @@ -8,8 +8,8 @@ MEMORY FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* entire flash */ FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 */ FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 5-11 are 128K */ - FLASH_FS (rx) : ORIGIN = 0x08100000, LENGTH = 256K /* sectors 12-17 are 4*16K+64K+128K */ - FLASH_FS2 (rx) : ORIGIN = 0x08140000, LENGTH = 128K /* sector 18 */ + FLASH_FS (rx) : ORIGIN = 0x08100000, LENGTH = 192K /* sectors 12-15 are 16K, 16 is 64K, 17 is 128K (64K used) */ + FLASH_FS2 (rx) : ORIGIN = 0x08140000, LENGTH = 64K /* sector 18 is 128K (64K used) */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K } @@ -28,3 +28,11 @@ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ _heap_end = _sstack; + +/* Filesystem cache in RAM, and storage in flash */ +_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(CCMRAM); +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); +_micropy_hw_internal_flash_storage2_start = ORIGIN(FLASH_FS2); +_micropy_hw_internal_flash_storage2_end = ORIGIN(FLASH_FS2) + LENGTH(FLASH_FS2); diff --git a/ports/stm32/boards/stm32f479_af.csv b/ports/stm32/boards/stm32f479_af.csv new file mode 100644 index 000000000..7cbb242a5 --- /dev/null +++ b/ports/stm32/boards/stm32f479_af.csv @@ -0,0 +1,161 @@ +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/2/3/4/5/6,SPI2/3/SAI1,SPI2/3/USART1/2/3,USART6/UART4/5/7/8,CAN1/2/TIM12/13/14/QUADSPI/LCD,QUADSPI/OTG2_HS/OTG1_FS,ETH,FMC/SDIO/OTG2_FS,DCMI/DSIHOST,LCD,SYS,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,QUADSPI_BK1_IO3,,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,LCD_R1,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS,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,,,,,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,,,,TIM14_CH1,QUADSPI_CLK,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,,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,,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,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3_EXTSD,,,,,,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,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,SDIO_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDIO_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,QUADSPI_BK1_NCS,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,,DSIHOST_TE,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,I2S2_EXTSD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,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,I2S2_EXTSD,,,,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,,,,,,,,,,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,,,,,,,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,,,SDIO_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,,,SDIO_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,,USART6_CK,,,,SDIO_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,,QUADSPI_BK1_IO0,,,SDIO_D1,DCMI_D3,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDIO_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,,,,I2S3_EXTSD,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDIO_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDIO_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,,,,SDIO_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,,,,,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,,,,,USART3_CTS,,QUADSPI_BK1_IO0,,,FMC_A16/FMC_CLE,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,QUADSPI_BK1_IO1,,,FMC_A17/FMC_ALE,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,,,,,,,QUADSPI_BK1_IO3,,,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,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,,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,,,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,,,,,,,,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,,,,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,,,FMC_D8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,,,FMC_D9,,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,,,FMC_D10,,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,,,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,,,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,,,SPI6_NSS,,,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT, +PortG,PG9,,,,,,,,,USART6_RX,QUADSPI_BK2_IO2,,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,,,,,,,,LCD_G3,,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,,,,,,,,,,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,,,,,SPI6_MISO,,,USART6_RTS,LCD_B4,,,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,TRACED0,,,,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG14,TRACED1,,,,,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,,,,,,,,,,QUADSPI_BK2_IO0,,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,,,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,,,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,,,,,,,,,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,,,,,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,I2S2_EXTSD,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,,,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,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,DSIHOST_TE,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, diff --git a/ports/stm32/boards/stm32f4xx_hal_conf_base.h b/ports/stm32/boards/stm32f4xx_hal_conf_base.h index f09990fd9..d42f3ba19 100644 --- a/ports/stm32/boards/stm32f4xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32f4xx_hal_conf_base.h @@ -42,6 +42,7 @@ #include "stm32f4xx_hal_i2c.h" #include "stm32f4xx_hal_i2s.h" #include "stm32f4xx_hal_iwdg.h" +#include "stm32f4xx_hal_mmc.h" #include "stm32f4xx_hal_pcd.h" #include "stm32f4xx_hal_pwr.h" #include "stm32f4xx_hal_rcc.h" @@ -74,6 +75,7 @@ #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 diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld index 8cf8a4e59..ad1b1b892 100644 --- a/ports/stm32/boards/stm32h743.ld +++ b/ports/stm32/boards/stm32h743.ld @@ -5,12 +5,11 @@ /* Specify the memory areas */ MEMORY { - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K - FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* sector 0, 128K */ - FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* sector 1, 128K */ - FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1792K /* sectors 6*128 + 8*128 */ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1536K /* sectors (0-7) + (0-3) */ + FLASH_APP (rx) : ORIGIN = 0x08020000, LENGTH = 1408K /* sectors (1-7) + (0-3) */ + FLASH_FS (r) : ORIGIN = 0x08180000, LENGTH = 512K /* sectors (4-7) */ DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ - RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM */ + RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM */ RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K } @@ -29,6 +28,14 @@ _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ _heap_end = _sstack; +/* Location of filesystem RAM cache */ +_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(DTCM); +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(DTCM) + LENGTH(DTCM); + +/* Location of filesystem flash storage */ +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); + /* Define output sections */ SECTIONS { diff --git a/ports/stm32/boards/stm32h7b3.ld b/ports/stm32/boards/stm32h7b3.ld new file mode 100644 index 000000000..cccea983f --- /dev/null +++ b/ports/stm32/boards/stm32h7b3.ld @@ -0,0 +1,30 @@ +/* + GNU linker script for STM32H7B3 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* sector 0, 128K */ + FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* sector 1, 128K */ + FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1792K /* sectors 6*128 + 8*128 */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM */ + RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K +} + +/* 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 */ + +/* 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 = _sstack; diff --git a/ports/stm32/boards/stm32h7b3_af.csv b/ports/stm32/boards/stm32h7b3_af.csv new file mode 100644 index 000000000..0e1747161 --- /dev/null +++ b/ports/stm32/boards/stm32h7b3_af.csv @@ -0,0 +1,175 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,I2S6_WS/SPI6_NSS,,USART2_CTS/USART2_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,,,,,EVENTOUT/EVENTOUT,ADC1_INP16, +PortA,PA0_C,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,I2S6_WS/SPI6_NSS,,USART2_CTS/USART2_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,,,,,EVENTOUT/EVENTOUT,ADC1_INP16, +PortA,PA1,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_DE/USART2_RTS,UART4_RX,OCTOSPIM_P1_IO3,SAI2_MCLK_B,OCTOSPIM_P1_DQS,,,LTDC_R2,EVENTOUT/EVENTOUT,ADC1_INN16/ADC1_INP17, +PortA,PA10,,TIM1_CH3,,LPUART1_RX,,,,USART1_RX,,,USB_OTG_HS_ID,MDIOS_MDIO,LTDC_B4,DCMI_D1/PSSI_D1,LTDC_B1,EVENTOUT/EVENTOUT,, +PortA,PA11,,TIM1_CH4,,LPUART1_CTS,,I2S2_WS/SPI2_NSS,UART4_RX,USART1_CTS/USART1_NSS,,FDCAN1_RX,,,,,LTDC_R4,EVENTOUT/EVENTOUT,, +PortA,PA12,,TIM1_ETR,,LPUART1_DE/LPUART1_RTS,,I2S2_CK/SPI2_SCK,UART4_TX,USART1_DE/USART1_RTS,SAI2_FS_B,FDCAN1_TX,,,,,LTDC_R5,EVENTOUT/EVENTOUT,, +PortA,PA13,DEBUG_JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,, +PortA,PA14,DEBUG_JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,, +PortA,PA15,DEBUG_JTDI,TIM2_CH1/TIM2_ETR,,,CEC,I2S1_WS/SPI1_NSS,I2S3_WS/SPI3_NSS,I2S6_WS/SPI6_NSS,UART4_DE/UART4_RTS,LTDC_R3,,UART7_TX,,,LTDC_B6,EVENTOUT/EVENTOUT,, +PortA,PA1_C,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_DE/USART2_RTS,UART4_RX,OCTOSPIM_P1_IO3,SAI2_MCLK_B,OCTOSPIM_P1_DQS,,,LTDC_R2,EVENTOUT/EVENTOUT,ADC1_INN16/ADC1_INP17, +PortA,PA2,,TIM2_CH3,TIM5_CH3,,TIM15_CH1,,DFSDM2_CKIN1,USART2_TX,SAI2_SCK_B,,,,MDIOS_MDIO,,LTDC_R1,EVENTOUT/EVENTOUT,ADC1_INP14, +PortA,PA3,,TIM2_CH4,TIM5_CH4,OCTOSPIM_P1_CLK,TIM15_CH2,I2S6_MCK,,USART2_RX,,LTDC_B2,USB_OTG_HS_ULPI_D0,,,,LTDC_B5,EVENTOUT/EVENTOUT,ADC1_INP15, +PortA,PA4,,,TIM5_ETR,,,I2S1_WS/SPI1_NSS,I2S3_WS/SPI3_NSS,USART2_CK,I2S6_WS/SPI6_NSS,,,,,DCMI_HSYNC/PSSI_DE,LTDC_VSYNC,EVENTOUT/EVENTOUT,ADC1_INP18, +PortA,PA5,PWR_NDSTOP2,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,I2S1_CK/SPI1_SCK,,,I2S6_CK/SPI6_SCK,,USB_OTG_HS_ULPI_CK,,,PSSI_D14,LTDC_R4,EVENTOUT/EVENTOUT,ADC1_INN18/ADC1_INP19, +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,I2S1_SDI/SPI1_MISO,OCTOSPIM_P1_IO3,,I2S6_SDI/SPI6_MISO,TIM13_CH1,TIM8_BKIN_COMP1/TIM8_BKIN_COMP2,MDIOS_MDC,TIM1_BKIN_COMP1/TIM1_BKIN_COMP2,DCMI_PIXCLK/PSSI_PDCK,LTDC_G2,EVENTOUT/EVENTOUT,ADC1_INP3/ADC2_INP3, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,DFSDM2_DATIN1,I2S1_SDO/SPI1_MOSI,,,I2S6_SDO/SPI6_MOSI,TIM14_CH1,OCTOSPIM_P1_IO2,,FMC_SDNWE,,LTDC_VSYNC,EVENTOUT/EVENTOUT,ADC1_INN3/ADC1_INP7/ADC2_INN3/ADC2_INP7, +PortA,PA8,RCC_MCO_1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,USB_OTG_HS_SOF,UART7_RX,TIM8_BKIN2_COMP1/TIM8_BKIN2_COMP2,LTDC_B3,LTDC_R6,EVENTOUT/EVENTOUT,, +PortA,PA9,,TIM1_CH2,,LPUART1_TX,I2C3_SMBA,I2S2_CK/SPI2_SCK,,USART1_TX,,,,,,DCMI_D0/PSSI_D0,LTDC_R5,EVENTOUT/EVENTOUT,, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,DFSDM2_CKOUT,,DFSDM1_CKOUT,,UART4_CTS,LTDC_R3,USB_OTG_HS_ULPI_D1,OCTOSPIM_P1_IO1,,,LTDC_G1,EVENTOUT/EVENTOUT,ADC1_INN5/ADC1_INP9/ADC2_INN5/ADC2_INP9, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATIN1,,,LTDC_R6,USB_OTG_HS_ULPI_D2,OCTOSPIM_P1_IO0,,,LTDC_G0,EVENTOUT/EVENTOUT,ADC1_INP5/ADC2_INP5, +PortB,PB10,,TIM2_CH3,,LPTIM2_IN1,I2C2_SCL,I2S2_CK/SPI2_SCK,DFSDM1_DATIN7,USART3_TX,,OCTOSPIM_P1_NCS,USB_OTG_HS_ULPI_D3,,,,LTDC_G4,EVENTOUT/EVENTOUT,, +PortB,PB11,,TIM2_CH4,,LPTIM2_ETR,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,USB_OTG_HS_ULPI_D4,,,,LTDC_G5,EVENTOUT/EVENTOUT,, +PortB,PB12,,TIM1_BKIN,,OCTOSPIM_P1_NCLK,I2C2_SMBA,I2S2_WS/SPI2_NSS,DFSDM1_DATIN1,USART3_CK,,FDCAN2_RX,USB_OTG_HS_ULPI_D5,DFSDM2_DATIN1,,TIM1_BKIN_COMP1/TIM1_BKIN_COMP2,UART5_RX,EVENTOUT/EVENTOUT,, +PortB,PB13,,TIM1_CH1N,,LPTIM2_OUT,DFSDM2_CKIN1,I2S2_CK/SPI2_SCK,DFSDM1_CKIN1,USART3_CTS/USART3_NSS,,FDCAN2_TX,USB_OTG_HS_ULPI_D6,,SDMMC1_D0,DCMI_D2/PSSI_D2,UART5_TX,EVENTOUT/EVENTOUT,, +PortB,PB14,,TIM1_CH2N,TIM12_CH1,TIM8_CH2N,USART1_TX,I2S2_SDI/SPI2_MISO,DFSDM1_DATIN2,USART3_DE/USART3_RTS,UART4_DE/UART4_RTS,SDMMC2_D0,,,,,LTDC_CLK,EVENTOUT/EVENTOUT,, +PortB,PB15,RTC_REFIN,TIM1_CH3N,TIM12_CH2,TIM8_CH3N,USART1_RX,I2S2_SDO/SPI2_MOSI,DFSDM1_CKIN2,,UART4_CTS,SDMMC2_D1,,,,,LTDC_G7,EVENTOUT/EVENTOUT,, +PortB,PB2,RTC_OUT_ALARM,,SAI1_D1,,DFSDM1_CKIN1,,SAI1_SD_A,I2S3_SDO/SPI3_MOSI,,OCTOSPIM_P1_CLK,OCTOSPIM_P1_DQS,,,,,EVENTOUT/EVENTOUT,, +PortB,PB3,DEBUG_JTDO/SWO,TIM2_CH2,,,,I2S1_CK/SPI1_SCK,I2S3_CK/SPI3_SCK,,I2S6_CK/SPI6_SCK,SDMMC2_D2,CRS_SYNC,UART7_RX,,,,EVENTOUT/EVENTOUT,, +PortB,PB4,,TIM16_BKIN,TIM3_CH1,,,I2S1_SDI/SPI1_MISO,I2S3_SDI/SPI3_MISO,I2S2_WS/SPI2_NSS,I2S6_SDI/SPI6_MISO,SDMMC2_D3,,UART7_TX,,,,EVENTOUT/EVENTOUT,, +PortB,PB5,,TIM17_BKIN,TIM3_CH2,,I2C1_SMBA,I2S1_SDO/SPI1_MOSI,I2C4_SMBA,I2S3_SDO/SPI3_MOSI,I2S6_SDO/SPI6_MOSI,FDCAN2_RX,USB_OTG_HS_ULPI_D7,LTDC_B5,FMC_SDCKE1,DCMI_D10/PSSI_D10,UART5_RX,EVENTOUT/EVENTOUT,, +PortB,PB6,,TIM16_CH1N,TIM4_CH1,,I2C1_SCL,CEC,I2C4_SCL,USART1_TX,LPUART1_TX,FDCAN2_TX,OCTOSPIM_P1_NCS,DFSDM1_DATIN5,FMC_SDNE1,DCMI_D5/PSSI_D5,UART5_TX,EVENTOUT/EVENTOUT,, +PortB,PB7,,TIM17_CH1N,TIM4_CH2,,I2C1_SDA,,I2C4_SDA,USART1_RX,LPUART1_RX,,,DFSDM1_CKIN5,FMC_NL,DCMI_VSYNC/PSSI_RDY,,EVENTOUT/EVENTOUT,, +PortB,PB8,,TIM16_CH1,TIM4_CH3,DFSDM1_CKIN7,I2C1_SCL,,I2C4_SCL,SDMMC1_CKIN,UART4_RX,FDCAN1_RX,SDMMC2_D4,,SDMMC1_D4,DCMI_D6/PSSI_D6,LTDC_B6,EVENTOUT/EVENTOUT,, +PortB,PB9,,TIM17_CH1,TIM4_CH4,DFSDM1_DATIN7,I2C1_SDA,I2S2_WS/SPI2_NSS,I2C4_SDA,SDMMC1_CDIR,UART4_TX,FDCAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7/PSSI_D7,LTDC_B7,EVENTOUT/EVENTOUT,, +PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATIN4,,SAI2_FS_B,FMC_A25,USB_OTG_HS_ULPI_STP,LTDC_G2,FMC_SDNWE,,LTDC_R5,EVENTOUT/EVENTOUT,ADC1_INP10/ADC2_INP10, +PortC,PC1,DEBUG_TRACED0,,SAI1_D1,DFSDM1_DATIN0,DFSDM1_CKIN4,I2S2_SDO/SPI2_MOSI,SAI1_SD_A,,,SDMMC2_CK,OCTOSPIM_P1_IO4,,MDIOS_MDC,,LTDC_G5,EVENTOUT/EVENTOUT,ADC1_INN10/ADC1_INP11/ADC2_INN10/ADC2_INP11, +PortC,PC10,,,,DFSDM1_CKIN5,DFSDM2_CKIN0,,I2S3_CK/SPI3_SCK,USART3_TX,UART4_TX,OCTOSPIM_P1_IO1,LTDC_B1,SWPMI1_RX,SDMMC1_D2,DCMI_D8/PSSI_D8,LTDC_R2,EVENTOUT/EVENTOUT,, +PortC,PC11,,,,DFSDM1_DATIN5,DFSDM2_DATIN0,,I2S3_SDI/SPI3_MISO,USART3_RX,UART4_RX,OCTOSPIM_P1_NCS,,,SDMMC1_D3,DCMI_D4/PSSI_D4,LTDC_B4,EVENTOUT/EVENTOUT,, +PortC,PC12,DEBUG_TRACED3,,TIM15_CH1,,DFSDM2_CKOUT,I2S6_CK/SPI6_SCK,I2S3_SDO/SPI3_MOSI,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9/PSSI_D9,LTDC_R6,EVENTOUT/EVENTOUT,, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,, +PortC,PC14-OSC32_IN,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,, +PortC,PC15-OSC32_OUT,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,, +PortC,PC2,PWR_CSTOP,,,DFSDM1_CKIN1,,I2S2_SDI/SPI2_MISO,DFSDM1_CKOUT,,,OCTOSPIM_P1_IO2,USB_OTG_HS_ULPI_DIR,OCTOSPIM_P1_IO5,FMC_SDNE0,,,EVENTOUT/EVENTOUT,ADC1_INN11/ADC1_INP12/ADC2_INN11/ADC2_INP12, +PortC,PC2_C,PWR_CSTOP,,,DFSDM1_CKIN1,,I2S2_SDI/SPI2_MISO,DFSDM1_CKOUT,,,OCTOSPIM_P1_IO2,USB_OTG_HS_ULPI_DIR,OCTOSPIM_P1_IO5,FMC_SDNE0,,,EVENTOUT/EVENTOUT,ADC1_INN11/ADC1_INP12/ADC2_INN11/ADC2_INP12, +PortC,PC3,PWR_CSLEEP,,,DFSDM1_DATIN1,,I2S2_SDO/SPI2_MOSI,,,,OCTOSPIM_P1_IO0,USB_OTG_HS_ULPI_NXT,OCTOSPIM_P1_IO6,FMC_SDCKE0,,,EVENTOUT/EVENTOUT,ADC2_INP1, +PortC,PC3_C,PWR_CSLEEP,,,DFSDM1_DATIN1,,I2S2_SDO/SPI2_MOSI,,,,OCTOSPIM_P1_IO0,USB_OTG_HS_ULPI_NXT,OCTOSPIM_P1_IO6,FMC_SDCKE0,,,EVENTOUT/EVENTOUT,ADC2_INP1, +PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,,SPDIFRX_IN3,,,FMC_SDNE0,,LTDC_R7,EVENTOUT/EVENTOUT,ADC1_INP4/ADC2_INP4, +PortC,PC5,,,SAI1_D3,DFSDM1_DATIN2,PSSI_D15,,,,,SPDIFRX_IN4,OCTOSPIM_P1_DQS,,FMC_SDCKE0,COMP1_OUT,LTDC_DE,EVENTOUT/EVENTOUT,ADC1_INN4/ADC1_INP8/ADC2_INN4/ADC2_INP8, +PortC,PC6,,,TIM3_CH1,TIM8_CH1,DFSDM1_CKIN3,I2S2_MCK,,USART6_TX,SDMMC1_D0DIR,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0/PSSI_D0,LTDC_HSYNC,EVENTOUT/EVENTOUT,, +PortC,PC7,DEBUG_TRGIO,,TIM3_CH2,TIM8_CH2,DFSDM1_DATIN3,,I2S3_MCK,USART6_RX,SDMMC1_D123DIR,FMC_NE1,SDMMC2_D7,SWPMI1_TX,SDMMC1_D7,DCMI_D1/PSSI_D1,LTDC_G6,EVENTOUT/EVENTOUT,, +PortC,PC8,DEBUG_TRACED1,,TIM3_CH3,TIM8_CH3,,,,USART6_CK,UART5_DE/UART5_RTS,FMC_NCE/FMC_NE2,FMC_INT,SWPMI1_RX,SDMMC1_D0,DCMI_D2/PSSI_D2,,EVENTOUT/EVENTOUT,, +PortC,PC9,RCC_MCO_2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,UART5_CTS,OCTOSPIM_P1_IO0,LTDC_G3,SWPMI1_SUSPEND,SDMMC1_D1,DCMI_D3/PSSI_D3,LTDC_B2,EVENTOUT/EVENTOUT,, +PortD,PD0,,,,DFSDM1_CKIN6,,,,,UART4_RX,FDCAN1_RX,,UART9_CTS,FMC_D2/FMC_DA2,,LTDC_B1,EVENTOUT/EVENTOUT,, +PortD,PD1,,,,DFSDM1_DATIN6,,,,,UART4_TX,FDCAN1_TX,,,FMC_D3/FMC_DA3,,,EVENTOUT/EVENTOUT,, +PortD,PD10,,,,DFSDM1_CKOUT,DFSDM2_CKOUT,,,USART3_CK,,,,,FMC_D15/FMC_DA15,,LTDC_B3,EVENTOUT/EVENTOUT,, +PortD,PD11,,,,LPTIM2_IN2,I2C4_SMBA,,,USART3_CTS/USART3_NSS,,OCTOSPIM_P1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT/EVENTOUT,, +PortD,PD12,,LPTIM1_IN1,TIM4_CH1,LPTIM2_IN1,I2C4_SCL,,,USART3_DE/USART3_RTS,,OCTOSPIM_P1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,DCMI_D12/PSSI_D12,,EVENTOUT/EVENTOUT,, +PortD,PD13,,LPTIM1_OUT,TIM4_CH2,,I2C4_SDA,,,,,OCTOSPIM_P1_IO3,SAI2_SCK_A,UART9_DE/UART9_RTS,FMC_A18,DCMI_D13/PSSI_D13,,EVENTOUT/EVENTOUT,, +PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,UART9_RX,FMC_D0/FMC_DA0,,,EVENTOUT/EVENTOUT,, +PortD,PD15,,,TIM4_CH4,,,,,,UART8_DE/UART8_RTS,,,UART9_TX,FMC_D1/FMC_DA1,,,EVENTOUT/EVENTOUT,, +PortD,PD2,DEBUG_TRACED2,,TIM3_ETR,,TIM15_BKIN,,,,UART5_RX,LTDC_B7,,,SDMMC1_CMD,DCMI_D11/PSSI_D11,LTDC_B2,EVENTOUT/EVENTOUT,, +PortD,PD3,,,,DFSDM1_CKOUT,,I2S2_CK/SPI2_SCK,,USART2_CTS/USART2_NSS,,,,,FMC_CLK,DCMI_D5/PSSI_D5,LTDC_G7,EVENTOUT/EVENTOUT,, +PortD,PD4,,,,,,,,USART2_DE/USART2_RTS,,,OCTOSPIM_P1_IO4,,FMC_NOE,,,EVENTOUT/EVENTOUT,, +PortD,PD5,,,,,,,,USART2_TX,,,OCTOSPIM_P1_IO5,,FMC_NWE,,,EVENTOUT/EVENTOUT,, +PortD,PD6,,,SAI1_D1,DFSDM1_CKIN4,DFSDM1_DATIN1,I2S3_SDO/SPI3_MOSI,SAI1_SD_A,USART2_RX,,,OCTOSPIM_P1_IO6,SDMMC2_CK,FMC_NWAIT,DCMI_D10/PSSI_D10,LTDC_B2,EVENTOUT/EVENTOUT,, +PortD,PD7,,,,DFSDM1_DATIN4,,I2S1_SDO/SPI1_MOSI,DFSDM1_CKIN1,USART2_CK,,SPDIFRX_IN1,OCTOSPIM_P1_IO7,SDMMC2_CMD,FMC_NE1,,,EVENTOUT/EVENTOUT,, +PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,,SPDIFRX_IN2,,,FMC_D13/FMC_DA13,,,EVENTOUT/EVENTOUT,, +PortD,PD9,,,,DFSDM1_DATIN3,,,,USART3_RX,,,,,FMC_D14/FMC_DA14,,,EVENTOUT/EVENTOUT,, +PortD,PDR_ON,,,,,,,,,,,,,,,,EVENTOUT,, +PortE,PE0,,LPTIM1_ETR,TIM4_ETR,,LPTIM2_ETR,,,,UART8_RX,,SAI2_MCLK_A,,FMC_NBL0,DCMI_D2/PSSI_D2,LTDC_R0,EVENTOUT/EVENTOUT,, +PortE,PE1,,LPTIM1_IN2,,,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3/PSSI_D3,LTDC_R6,EVENTOUT/EVENTOUT,, +PortE,PE10,,TIM1_CH2N,,DFSDM1_DATIN4,,,,UART7_CTS,,,OCTOSPIM_P1_IO7,,FMC_D7/FMC_DA7,,,EVENTOUT/EVENTOUT,, +PortE,PE11,,TIM1_CH2,,DFSDM1_CKIN4,,SPI4_NSS,,,,,SAI2_SD_B,OCTOSPIM_P1_NCS,FMC_D8/FMC_DA8,,LTDC_G3,EVENTOUT/EVENTOUT,, +PortE,PE12,,TIM1_CH3N,,DFSDM1_DATIN5,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9/FMC_DA9,COMP1_OUT,LTDC_B4,EVENTOUT/EVENTOUT,, +PortE,PE13,,TIM1_CH3,,DFSDM1_CKIN5,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10/FMC_DA10,COMP2_OUT,LTDC_DE,EVENTOUT/EVENTOUT,, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCLK_B,,FMC_D11/FMC_DA11,,LTDC_CLK,EVENTOUT/EVENTOUT,, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,USART10_CK,FMC_D12/FMC_DA12,TIM1_BKIN_COMP1/TIM1_BKIN_COMP2,LTDC_R7,EVENTOUT/EVENTOUT,, +PortE,PE2,DEBUG_TRACECLK,,SAI1_CK1,,,SPI4_SCK,SAI1_MCLK_A,,,OCTOSPIM_P1_IO2,,USART10_RX,FMC_A23,,,EVENTOUT/EVENTOUT,, +PortE,PE3,DEBUG_TRACED0,,,,TIM15_BKIN,,SAI1_SD_B,,,,,USART10_TX,FMC_A19,,,EVENTOUT/EVENTOUT,, +PortE,PE4,DEBUG_TRACED1,,SAI1_D2,DFSDM1_DATIN3,TIM15_CH1N,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4/PSSI_D4,LTDC_B0,EVENTOUT/EVENTOUT,, +PortE,PE5,DEBUG_TRACED2,,SAI1_CK2,DFSDM1_CKIN3,TIM15_CH1,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6/PSSI_D6,LTDC_G0,EVENTOUT/EVENTOUT,, +PortE,PE6,DEBUG_TRACED3,TIM1_BKIN2,SAI1_D1,,TIM15_CH2,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCLK_B,TIM1_BKIN2_COMP1/TIM1_BKIN2_COMP2,FMC_A22,DCMI_D7/PSSI_D7,LTDC_G1,EVENTOUT/EVENTOUT,, +PortE,PE7,,TIM1_ETR,,DFSDM1_DATIN2,,,,UART7_RX,,,OCTOSPIM_P1_IO4,,FMC_D4/FMC_DA4,,,EVENTOUT/EVENTOUT,, +PortE,PE8,,TIM1_CH1N,,DFSDM1_CKIN2,,,,UART7_TX,,,OCTOSPIM_P1_IO5,,FMC_D5/FMC_DA5,COMP2_OUT,,EVENTOUT/EVENTOUT,, +PortE,PE9,,TIM1_CH1,,DFSDM1_CKOUT,,,,UART7_DE/UART7_RTS,,,OCTOSPIM_P1_IO6,,FMC_D6/FMC_DA6,,,EVENTOUT/EVENTOUT,, +PortF,PF0,,,,,I2C2_SDA,,,,,OCTOSPIM_P2_IO0,,,FMC_A0,,,EVENTOUT/EVENTOUT,, +PortF,PF1,,,,,I2C2_SCL,,,,,OCTOSPIM_P2_IO1,,,FMC_A1,,,EVENTOUT/EVENTOUT,, +PortF,PF10,,TIM16_BKIN,SAI1_D3,,PSSI_D15,,,,,OCTOSPIM_P1_CLK,,,,DCMI_D11/PSSI_D11,LTDC_DE,EVENTOUT/EVENTOUT,, +PortF,PF11,,,,,,SPI5_MOSI,,,,OCTOSPIM_P1_NCLK,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12/PSSI_D12,,EVENTOUT/EVENTOUT,ADC1_INP2, +PortF,PF12,,,,,,,,,,OCTOSPIM_P2_DQS,,,FMC_A6,,,EVENTOUT/EVENTOUT,ADC1_INN2/ADC1_INP6, +PortF,PF13,,,,DFSDM1_DATIN6,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT/EVENTOUT,ADC2_INP2, +PortF,PF14,,,,DFSDM1_CKIN6,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT/EVENTOUT,ADC2_INN2/ADC2_INP6, +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT/EVENTOUT,, +PortF,PF2,,,,,I2C2_SMBA,,,,,OCTOSPIM_P2_IO2,,,FMC_A2,,,EVENTOUT/EVENTOUT,, +PortF,PF3,,,,,,,,,,OCTOSPIM_P2_IO3,,,FMC_A3,,,EVENTOUT/EVENTOUT,, +PortF,PF4,,,,,,,,,,OCTOSPIM_P2_CLK,,,FMC_A4,,,EVENTOUT/EVENTOUT,, +PortF,PF5,,,,,,,,,,OCTOSPIM_P2_NCLK,,,FMC_A5,,,EVENTOUT/EVENTOUT,, +PortF,PF6,,TIM16_CH1,,,,SPI5_NSS,SAI1_SD_B,UART7_RX,,,OCTOSPIM_P1_IO3,,,,,EVENTOUT/EVENTOUT,, +PortF,PF7,,TIM17_CH1,,,,SPI5_SCK,SAI1_MCLK_B,UART7_TX,,,OCTOSPIM_P1_IO2,,,,,EVENTOUT/EVENTOUT,, +PortF,PF8,,TIM16_CH1N,,,,SPI5_MISO,SAI1_SCK_B,UART7_DE/UART7_RTS,,TIM13_CH1,OCTOSPIM_P1_IO0,,,,,EVENTOUT/EVENTOUT,, +PortF,PF9,,TIM17_CH1N,,,,SPI5_MOSI,SAI1_FS_B,UART7_CTS,,TIM14_CH1,OCTOSPIM_P1_IO1,,,,,EVENTOUT/EVENTOUT,, +PortG,PG0,,,,,,,,,,OCTOSPIM_P2_IO4,,UART9_RX,FMC_A10,,,EVENTOUT/EVENTOUT,, +PortG,PG1,,,,,,,,,,OCTOSPIM_P2_IO5,,UART9_TX,FMC_A11,,,EVENTOUT/EVENTOUT,, +PortG,PG10,,,,OCTOSPIM_P2_IO6,,I2S1_WS/SPI1_NSS,,,,LTDC_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2/PSSI_D2,LTDC_B2,EVENTOUT/EVENTOUT,, +PortG,PG11,,LPTIM1_IN2,,,,I2S1_CK/SPI1_SCK,,,SPDIFRX_IN1,OCTOSPIM_P2_IO7,SDMMC2_D2,USART10_RX,,DCMI_D3/PSSI_D3,LTDC_B3,EVENTOUT/EVENTOUT,, +PortG,PG12,,LPTIM1_IN1,,OCTOSPIM_P2_NCS,,I2S6_SDI/SPI6_MISO,,USART6_DE/USART6_RTS,SPDIFRX_IN2,LTDC_B4,SDMMC2_D3,USART10_TX,FMC_NE4,,LTDC_B1,EVENTOUT/EVENTOUT,, +PortG,PG13,DEBUG_TRACED0,LPTIM1_OUT,,,,I2S6_CK/SPI6_SCK,,USART6_CTS/USART6_NSS,,,SDMMC2_D6,USART10_CTS/USART10_NSS,FMC_A24,,LTDC_R0,EVENTOUT/EVENTOUT,, +PortG,PG14,DEBUG_TRACED1,LPTIM1_ETR,,,,I2S6_SDO/SPI6_MOSI,,USART6_TX,,OCTOSPIM_P1_IO7,SDMMC2_D7,USART10_DE/USART10_RTS,FMC_A25,,LTDC_B0,EVENTOUT/EVENTOUT,, +PortG,PG15,,,,,,,,USART6_CTS/USART6_NSS,,OCTOSPIM_P2_DQS,,USART10_CK,FMC_SDNCAS,DCMI_D13/PSSI_D13,,EVENTOUT/EVENTOUT,, +PortG,PG2,,,,TIM8_BKIN,,,,,,,,TIM8_BKIN_COMP1/TIM8_BKIN_COMP2,FMC_A12,,,EVENTOUT/EVENTOUT,, +PortG,PG3,,,,TIM8_BKIN2,,,,,,,,TIM8_BKIN2_COMP1/TIM8_BKIN2_COMP2,FMC_A13,,,EVENTOUT/EVENTOUT,, +PortG,PG4,,TIM1_BKIN2,,,,,,,,,,TIM1_BKIN2_COMP1/TIM1_BKIN2_COMP2,FMC_A14/FMC_BA0,,,EVENTOUT/EVENTOUT,, +PortG,PG5,,TIM1_ETR,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT/EVENTOUT,, +PortG,PG6,,TIM17_BKIN,,,,,,,,,OCTOSPIM_P1_NCS,,FMC_NE3,DCMI_D12/PSSI_D12,LTDC_R7,EVENTOUT/EVENTOUT,, +PortG,PG7,,,,,,,SAI1_MCLK_A,USART6_CK,,OCTOSPIM_P2_DQS,,,FMC_INT,DCMI_D13/PSSI_D13,LTDC_CLK,EVENTOUT/EVENTOUT,, +PortG,PG8,,,,TIM8_ETR,,I2S6_WS/SPI6_NSS,,USART6_DE/USART6_RTS,SPDIFRX_IN3,,,,FMC_SDCLK,,LTDC_G7,EVENTOUT/EVENTOUT,, +PortG,PG9,,,,,,I2S1_SDI/SPI1_MISO,,USART6_RX,SPDIFRX_IN4,OCTOSPIM_P1_IO6,SAI2_FS_B,SDMMC2_D0,FMC_NCE/FMC_NE2,DCMI_VSYNC/PSSI_RDY,,EVENTOUT/EVENTOUT,, +PortH,PH0-OSC_IN,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,, +PortH,PH1-OSC_OUT,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,, +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1/PSSI_D1,LTDC_R4,EVENTOUT/EVENTOUT,, +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2/PSSI_D2,LTDC_R5,EVENTOUT/EVENTOUT,, +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3/PSSI_D3,LTDC_R6,EVENTOUT/EVENTOUT,, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,FDCAN1_TX,,,FMC_D21,,LTDC_G2,EVENTOUT/EVENTOUT,, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,FDCAN1_RX,,,FMC_D22,DCMI_D4/PSSI_D4,LTDC_G3,EVENTOUT/EVENTOUT,, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11/PSSI_D11,LTDC_G4,EVENTOUT/EVENTOUT,, +PortH,PH2,,LPTIM1_IN2,,,,,,,,OCTOSPIM_P1_IO4,SAI2_SCK_B,,FMC_SDCKE0,,LTDC_R0,EVENTOUT/EVENTOUT,, +PortH,PH3,,,,,,,,,,OCTOSPIM_P1_IO5,SAI2_MCLK_B,,FMC_SDNE0,,LTDC_R1,EVENTOUT/EVENTOUT,, +PortH,PH4,,,,,I2C2_SCL,,,,,LTDC_G5,USB_OTG_HS_ULPI_NXT,,,PSSI_D14,LTDC_G4,EVENTOUT/EVENTOUT,, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT/EVENTOUT,, +PortH,PH6,,,TIM12_CH1,,I2C2_SMBA,SPI5_SCK,,,,,,,FMC_SDNE1,DCMI_D8/PSSI_D8,,EVENTOUT/EVENTOUT,, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,,FMC_SDCKE1,DCMI_D9/PSSI_D9,,EVENTOUT/EVENTOUT,, +PortH,PH8,,,TIM5_ETR,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC/PSSI_DE,LTDC_R2,EVENTOUT/EVENTOUT,, +PortH,PH9,,,TIM12_CH2,,I2C3_SMBA,,,,,,,,FMC_D17,DCMI_D0/PSSI_D0,LTDC_R3,EVENTOUT/EVENTOUT,, +PortI,PI0,,,TIM5_CH4,,,I2S2_WS/SPI2_NSS,,,,,,,FMC_D24,DCMI_D13/PSSI_D13,LTDC_G5,EVENTOUT/EVENTOUT,, +PortI,PI1,,,,TIM8_BKIN2,,I2S2_CK/SPI2_SCK,,,,,,TIM8_BKIN2_COMP1/TIM8_BKIN2_COMP2,FMC_D25,DCMI_D8/PSSI_D8,LTDC_G6,EVENTOUT/EVENTOUT,, +PortI,PI10,,,,OCTOSPIM_P2_IO1,,,,,,,,,FMC_D31,PSSI_D14,LTDC_HSYNC,EVENTOUT/EVENTOUT,, +PortI,PI11,,,,OCTOSPIM_P2_IO2,,,,,,LTDC_G6,USB_OTG_HS_ULPI_DIR,,,PSSI_D15,,EVENTOUT/EVENTOUT,, +PortI,PI12,,,,OCTOSPIM_P2_IO3,,,,,,,,,,,LTDC_HSYNC,EVENTOUT/EVENTOUT,, +PortI,PI13,,,,OCTOSPIM_P2_CLK,,,,,,,,,,,LTDC_VSYNC,EVENTOUT/EVENTOUT,, +PortI,PI14,,,,OCTOSPIM_P2_NCLK,,,,,,,,,,,LTDC_CLK,EVENTOUT/EVENTOUT,, +PortI,PI15,,,,,,,,,,LTDC_G2,,,,,LTDC_R0,EVENTOUT/EVENTOUT,, +PortI,PI2,,,,TIM8_CH4,,I2S2_SDI/SPI2_MISO,,,,,,,FMC_D26,DCMI_D9/PSSI_D9,LTDC_G7,EVENTOUT/EVENTOUT,, +PortI,PI3,,,,TIM8_ETR,,I2S2_SDO/SPI2_MOSI,,,,,,,FMC_D27,DCMI_D10/PSSI_D10,,EVENTOUT/EVENTOUT,, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCLK_A,TIM8_BKIN_COMP1/TIM8_BKIN_COMP2,FMC_NBL2,DCMI_D5/PSSI_D5,LTDC_B4,EVENTOUT/EVENTOUT,, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC/PSSI_RDY,LTDC_B5,EVENTOUT/EVENTOUT,, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6/PSSI_D6,LTDC_B6,EVENTOUT/EVENTOUT,, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7/PSSI_D7,LTDC_B7,EVENTOUT/EVENTOUT,, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT/EVENTOUT,, +PortI,PI9,,,,OCTOSPIM_P2_IO0,,,,,UART4_RX,FDCAN1_RX,,,FMC_D30,,LTDC_VSYNC,EVENTOUT/EVENTOUT,, +PortJ,PJ0,,,,,,,,,,LTDC_R7,,,,,LTDC_R1,EVENTOUT/EVENTOUT,, +PortJ,PJ1,,,,OCTOSPIM_P2_IO4,,,,,,,,,,,LTDC_R2,EVENTOUT/EVENTOUT,, +PortJ,PJ10,,TIM1_CH2N,,TIM8_CH2,,SPI5_MOSI,,,,,,,,,LTDC_G3,EVENTOUT/EVENTOUT,, +PortJ,PJ11,,TIM1_CH2,,TIM8_CH2N,,SPI5_MISO,,,,,,,,,LTDC_G4,EVENTOUT/EVENTOUT,, +PortJ,PJ12,DEBUG_TRGOUT,,,,,,,,,LTDC_G3,,,,,LTDC_B0,EVENTOUT/EVENTOUT,, +PortJ,PJ13,,,,,,,,,,LTDC_B4,,,,,LTDC_B1,EVENTOUT/EVENTOUT,, +PortJ,PJ14,,,,,,,,,,,,,,,LTDC_B2,EVENTOUT/EVENTOUT,, +PortJ,PJ15,,,,,,,,,,,,,,,LTDC_B3,EVENTOUT/EVENTOUT,, +PortJ,PJ2,,,,OCTOSPIM_P2_IO5,,,,,,,,,,,LTDC_R3,EVENTOUT/EVENTOUT,, +PortJ,PJ3,,,,,,,,,,,,UART9_DE/UART9_RTS,,,LTDC_R4,EVENTOUT/EVENTOUT,, +PortJ,PJ4,,,,,,,,,,,,UART9_CTS,,,LTDC_R5,EVENTOUT/EVENTOUT,, +PortJ,PJ5,,,,,,,,,,,,,,,LTDC_R6,EVENTOUT/EVENTOUT,, +PortJ,PJ6,,,,TIM8_CH2,,,,,,,,,,,LTDC_R7,EVENTOUT/EVENTOUT,, +PortJ,PJ7,DEBUG_TRGIN,,,TIM8_CH2N,,,,,,,,,,,LTDC_G0,EVENTOUT/EVENTOUT,, +PortJ,PJ8,,TIM1_CH3N,,TIM8_CH1,,,,,UART8_TX,,,,,,LTDC_G1,EVENTOUT/EVENTOUT,, +PortJ,PJ9,,TIM1_CH3,,TIM8_CH1N,,,,,UART8_RX,,,,,,LTDC_G2,EVENTOUT/EVENTOUT,, +PortK,PK0,,TIM1_CH1N,,TIM8_CH3,,SPI5_SCK,,,,,,,,,LTDC_G5,EVENTOUT/EVENTOUT,, +PortK,PK1,,TIM1_CH1,,TIM8_CH3N,,SPI5_NSS,,,,,,,,,LTDC_G6,EVENTOUT/EVENTOUT,, +PortK,PK2,,TIM1_BKIN,,TIM8_BKIN,,,,,,,TIM8_BKIN_COMP1/TIM8_BKIN_COMP2,TIM1_BKIN_COMP1/TIM1_BKIN_COMP2,,,LTDC_G7,EVENTOUT/EVENTOUT,, +PortK,PK3,,,,OCTOSPIM_P2_IO6,,,,,,,,,,,LTDC_B4,EVENTOUT/EVENTOUT,, +PortK,PK4,,,,OCTOSPIM_P2_IO7,,,,,,,,,,,LTDC_B5,EVENTOUT/EVENTOUT,, +PortK,PK5,,,,OCTOSPIM_P2_NCS,,,,,,,,,,,LTDC_B6,EVENTOUT/EVENTOUT,, +PortK,PK6,,,,OCTOSPIM_P2_DQS,,,,,,,,,,,LTDC_B7,EVENTOUT/EVENTOUT,, +PortK,PK7,,,,,,,,,,,,,,,LTDC_DE,EVENTOUT/EVENTOUT,, diff --git a/ports/stm32/boards/stm32l432.ld b/ports/stm32/boards/stm32l432.ld index 469e834f9..2006471e7 100644 --- a/ports/stm32/boards/stm32l432.ld +++ b/ports/stm32/boards/stm32l432.ld @@ -21,14 +21,14 @@ _minimum_heap_size = 16K; _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 */ +_micropy_hw_internal_flash_storage_ram_cache_end = _ram_end; +_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */ -_estack = _ram_fs_cache_start - _estack_reserve; +_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve; _sstack = _estack - 10K; /* stack = 10K */ _heap_start = _ebss; /* heap starts just after statically allocated memory */ _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); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l432_af.csv b/ports/stm32/boards/stm32l432_af.csv index e1d231c40..debfcd7b3 100644 --- a/ports/stm32/boards/stm32l432_af.csv +++ b/ports/stm32/boards/stm32l432_af.csv @@ -25,4 +25,4 @@ PortB,PB6,,LPTIM1_ETR,,,I2C1_SCL,,,USART1_TX,,TSC_G2_IO3,,,,SAI1_FS_B,TIM16_CH1N PortB,PB7,,LPTIM1_IN2,,,I2C1_SDA,,,USART1_RX,,TSC_G2_IO4,,,,,,EVENTOUT,,COMP2_INM, PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,, PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,, -PortH,PH3,,,,,,,,,,,,,,,,EVENTOUT,,, \ No newline at end of file +PortH,PH3,,,,,,,,,,,,,,,,EVENTOUT,,, diff --git a/ports/stm32/boards/stm32l452xe.ld b/ports/stm32/boards/stm32l452xe.ld index 7b07ee701..0cb753a1c 100644 --- a/ports/stm32/boards/stm32l452xe.ld +++ b/ports/stm32/boards/stm32l452xe.ld @@ -21,14 +21,14 @@ _minimum_heap_size = 16K; _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 */ +_micropy_hw_internal_flash_storage_ram_cache_end = _ram_end; +_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */ -_estack = _ram_fs_cache_start - _estack_reserve; +_estack = _micropy_hw_internal_flash_storage_ram_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); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld index 6eaf71545..1c70a9cfd 100644 --- a/ports/stm32/boards/stm32l476xe.ld +++ b/ports/stm32/boards/stm32l476xe.ld @@ -22,14 +22,14 @@ _minimum_heap_size = 16K; _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 */ +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); /* fs_cache in SRAM2 */ +_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */ -_estack = _ram_fs_cache_start - _estack_reserve; /* stack in SRAM2 */ +_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve; /* stack in SRAM2 */ _sstack = ORIGIN(SRAM2); /* stack = 30K */ _heap_start = _ebss; /* heap starts just after statically allocated memory */ _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); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld index 09c3f29c5..0185eb1b2 100644 --- a/ports/stm32/boards/stm32l476xg.ld +++ b/ports/stm32/boards/stm32l476xg.ld @@ -22,14 +22,14 @@ _minimum_heap_size = 16K; _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 */ +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(SRAM2) + LENGTH(SRAM2); /* fs_cache in SRAM2 */ +_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */ -_estack = _ram_fs_cache_start - _estack_reserve; /* stack in SRAM2 */ +_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve; /* stack in SRAM2 */ _sstack = ORIGIN(SRAM2); /* stack = 30K */ _heap_start = _ebss; /* heap starts just after statically allocated memory */ _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); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l496xg.ld b/ports/stm32/boards/stm32l496xg.ld index 327cb5ce1..d7cb92b8d 100644 --- a/ports/stm32/boards/stm32l496xg.ld +++ b/ports/stm32/boards/stm32l496xg.ld @@ -21,14 +21,14 @@ _minimum_heap_size = 16K; _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 */ +_micropy_hw_internal_flash_storage_ram_cache_end = _ram_end; +_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_cache_end - 2K; /* fs cache = 2K */ -_estack = _ram_fs_cache_start - _estack_reserve; +_estack = _micropy_hw_internal_flash_storage_ram_cache_start - _estack_reserve; _sstack = _estack - 16K; /* stack = 16K */ _heap_start = _ebss; /* heap starts just after statically allocated memory */ _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); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l4xx_hal_conf_base.h b/ports/stm32/boards/stm32l4xx_hal_conf_base.h index 4f3a78d50..ce35dee28 100644 --- a/ports/stm32/boards/stm32l4xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32l4xx_hal_conf_base.h @@ -26,10 +26,13 @@ #ifndef MICROPY_INCLUDED_STM32L4XX_HAL_CONF_BASE_H #define MICROPY_INCLUDED_STM32L4XX_HAL_CONF_BASE_H +// Needs to be defined before ll_usb.h is included +#define HAL_PCD_MODULE_ENABLED + // Include various HAL modules for convenience #include "stm32l4xx_hal_dma.h" #include "stm32l4xx_hal_adc.h" -#include "stm32l4xx_hal_can.h" +#include "Legacy/stm32l4xx_hal_can_legacy.h" #include "stm32l4xx_hal_cortex.h" #include "stm32l4xx_hal_crc.h" #include "stm32l4xx_hal_dac.h" @@ -54,11 +57,12 @@ #include "stm32l4xx_ll_lpuart.h" #include "stm32l4xx_ll_rtc.h" #include "stm32l4xx_ll_usart.h" +#include "stm32l4xx_ll_usb.h" // Enable various HAL modules #define HAL_MODULE_ENABLED #define HAL_ADC_MODULE_ENABLED -#define HAL_CAN_MODULE_ENABLED +#define HAL_CAN_LEGACY_MODULE_ENABLED #define HAL_CORTEX_MODULE_ENABLED #define HAL_CRC_MODULE_ENABLED #define HAL_DAC_MODULE_ENABLED @@ -70,7 +74,6 @@ #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 diff --git a/ports/stm32/boards/stm32wb55xg.ld b/ports/stm32/boards/stm32wb55xg.ld index c3dc5f519..841c32b8a 100644 --- a/ports/stm32/boards/stm32wb55xg.ld +++ b/ports/stm32/boards/stm32wb55xg.ld @@ -21,19 +21,19 @@ _minimum_heap_size = 16K; _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 */ +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(RAM) + LENGTH(RAM); +_micropy_hw_internal_flash_storage_ram_cache_start = _micropy_hw_internal_flash_storage_ram_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; +_estack = _micropy_hw_internal_flash_storage_ram_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); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); SECTIONS { diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index ba09dc170..b376ee23b 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -42,6 +42,10 @@ #define ENABLE_SDIO (MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD || MICROPY_PY_NETWORK_CYW43) +// If the CYW43 driver is enabled then SDIO DMA can happen preemptively (on an +// IRQ) and so the SDIO needs exclusive access to its DMA resource. +#define SDIO_NEEDS_EXCLUSIVE_DMA_ACCESS (MICROPY_PY_NETWORK_CYW43 && MICROPY_HW_SDIO_SDMMC == 1) + typedef enum { dma_id_not_defined=-1, dma_id_0, @@ -298,11 +302,13 @@ const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, dma_id_10, &dma #if MICROPY_HW_ENABLE_I2S const dma_descr_t dma_I2S_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, dma_id_10, &dma_init_struct_i2s }; #endif -const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, dma_id_11, &dma_init_struct_spi_i2c }; #if ENABLE_SDIO const dma_descr_t dma_SDIO_0 = { DMA2_Stream3, DMA_CHANNEL_4, dma_id_11, &dma_init_struct_sdio }; #endif +#if !SDIO_NEEDS_EXCLUSIVE_DMA_ACCESS +const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, dma_id_11, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_CHANNEL_5, dma_id_11, &dma_init_struct_spi_i2c }; +#endif const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, dma_id_12, &dma_init_struct_spi_i2c }; 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 }; @@ -1233,3 +1239,13 @@ void dma_nohal_start(const dma_descr_t *descr, uint32_t src_addr, uint32_t dst_a } #endif + +#define DMA_ID_FROM_CONTROLLER_STREAM(c, s) ((s) + (c) * NSTREAMS_PER_CONTROLLER) + +void dma_external_acquire(uint32_t controller, uint32_t stream) { + dma_enable_clock(DMA_ID_FROM_CONTROLLER_STREAM(controller, stream)); +} + +void dma_external_release(uint32_t controller, uint32_t stream) { + dma_disable_clock(DMA_ID_FROM_CONTROLLER_STREAM(controller, stream)); +} diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 8bd101a61..00200bae4 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -102,13 +102,21 @@ extern const dma_descr_t dma_I2C_4_RX; #endif +// API that configures the DMA via the HAL. 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); +// API that configures the DMA directly and does not use the HAL. 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); +// API to be used if DMA is controlled externally, to ensure the clock remains enabled. +// - controller: should be 0 or 1, corresponding to DMA1 or DMA2 +// - stream: should be 0 to N, corresponding to Stream0..StreamN, or Channel1..ChannelN +void dma_external_acquire(uint32_t controller, uint32_t stream); +void dma_external_release(uint32_t controller, uint32_t stream); + #endif // MICROPY_INCLUDED_STM32_DMA_H diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c index f174b6af0..be418235e 100644 --- a/ports/stm32/eth.c +++ b/ports/stm32/eth.c @@ -29,7 +29,7 @@ #include "py/mperrno.h" #include "shared/netutils/netutils.h" #include "pin_static_af.h" -#include "modnetwork.h" +#include "extmod/modnetwork.h" #include "mpu.h" #include "eth.h" diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 695655f09..699bc6004 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -166,7 +166,11 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { #if defined(STM32H7) PVD_AVD_IRQn, RTC_Alarm_IRQn, + #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + RTC_TAMP_STAMP_CSS_LSE_IRQn, + #else TAMP_STAMP_IRQn, + #endif RTC_WKUP_IRQn, #elif defined(STM32WB) PVD_PVM_IRQn, diff --git a/ports/stm32/factoryreset.c b/ports/stm32/factoryreset.c index 725ecd12a..10eb3a17a 100644 --- a/ports/stm32/factoryreset.c +++ b/ports/stm32/factoryreset.c @@ -37,8 +37,8 @@ #if MICROPY_VFS_FAT 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" + "# boot.py -- run on boot to configure USB and filesystem\r\n" + "# Put app code in main.py\r\n" "\r\n" "import machine\r\n" "import pyb\r\n" @@ -109,6 +109,7 @@ MP_WEAK int factory_reset_create_filesystem(void) { uint32_t start_tick = HAL_GetTick(); fs_user_mount_t vfs; + vfs.blockdev.flags = 0; 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)); diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index d399ece86..b926679f9 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -253,7 +253,11 @@ int flash_erase(uint32_t flash_dest, uint32_t num_word32) { #endif EraseInitStruct.TypeErase = TYPEERASE_SECTORS; + #if defined(FLASH_CR_PSIZE) EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + #else + EraseInitStruct.VoltageRange = 0; // unused parameter on STM32H7A3/B3 + #endif #if defined(STM32H7) EraseInitStruct.Banks = get_bank(flash_dest); #endif diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c index 6ed891300..946a9d8cc 100644 --- a/ports/stm32/flashbdev.c +++ b/ports/stm32/flashbdev.c @@ -61,31 +61,13 @@ 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) +#elif defined(STM32F427xx) || defined(STM32F429xx) #define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k #define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM #define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 #define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k -#elif defined(STM32F439xx) - -#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k -#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM -#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12 -#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k -#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18 -#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k) - #elif defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) #define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k @@ -102,37 +84,36 @@ STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k #define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1 #define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k -#elif defined(STM32H743xx) - -// The STM32H743 flash sectors are 128K -#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 128k -#define FLASH_SECTOR_SIZE_MAX (0x20000) // 128k max -#define FLASH_MEM_SEG1_START_ADDR (0x08020000) // sector 1 -#define FLASH_MEM_SEG1_NUM_BLOCKS (256) // Sector 1: 128k / 512b = 256 blocks - -#elif defined(STM32L432xx) || \ - defined(STM32L451xx) || defined(STM32L452xx) || defined(STM32L462xx) || \ - 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. -extern uint8_t _flash_fs_start; -extern uint8_t _flash_fs_end; -extern uint8_t _ram_fs_cache_start[]; // size determined by linker file -extern uint8_t _ram_fs_cache_end[]; - -#define CACHE_MEM_START_ADDR ((uintptr_t)&_ram_fs_cache_start[0]) -#define FLASH_SECTOR_SIZE_MAX (&_ram_fs_cache_end[0] - &_ram_fs_cache_start[0]) // 2k max -#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start) -#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512) - #else -#error "no internal flash storage support for this MCU" + +// Generic configuration where the linker script specifies flash storage and RAM cache locations. + +extern uint8_t _micropy_hw_internal_flash_storage_start; +extern uint8_t _micropy_hw_internal_flash_storage_end; +extern uint8_t _micropy_hw_internal_flash_storage2_start; +extern uint8_t _micropy_hw_internal_flash_storage2_end; +extern uint8_t _micropy_hw_internal_flash_storage_ram_cache_start[]; +extern uint8_t _micropy_hw_internal_flash_storage_ram_cache_end[]; + +#define CACHE_MEM_START_ADDR \ + ((uintptr_t)&_micropy_hw_internal_flash_storage_ram_cache_start[0]) +#define FLASH_SECTOR_SIZE_MAX \ + (&_micropy_hw_internal_flash_storage_ram_cache_end[0] - &_micropy_hw_internal_flash_storage_ram_cache_start[0]) +#define FLASH_MEM_SEG1_START_ADDR \ + ((long)&_micropy_hw_internal_flash_storage_start) +#define FLASH_MEM_SEG1_NUM_BLOCKS \ + ((&_micropy_hw_internal_flash_storage_end - &_micropy_hw_internal_flash_storage_start) / 512) + +#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE_SEGMENT2 +#define FLASH_MEM_SEG2_START_ADDR \ + ((long)&_micropy_hw_internal_flash_storage2_start) +#define FLASH_MEM_SEG2_NUM_BLOCKS \ + ((&_micropy_hw_internal_flash_storage2_end - &_micropy_hw_internal_flash_storage2_start) / 512) +#endif + #endif #if !defined(FLASH_MEM_SEG2_START_ADDR) -#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment #define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment #endif @@ -215,9 +196,11 @@ static uint32_t convert_block_to_flash_addr(uint32_t block) { if (block < FLASH_MEM_SEG1_NUM_BLOCKS) { return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE; } + #ifdef FLASH_MEM_SEG2_START_ADDR if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) { return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE; } + #endif // can add more flash segments here if needed, following above pattern // bad block diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 0b7105344..c63fe2162 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -268,7 +268,12 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { return num_acks; } -#elif defined(STM32F0) || defined(STM32F7) +#elif defined(STM32F0) || defined(STM32F7) || defined(STM32H7) + +#if defined(STM32H7) +#define APB1ENR APB1LENR +#define RCC_APB1ENR_I2C1EN RCC_APB1LENR_I2C1EN +#endif STATIC uint16_t i2c_timeout_ms[MICROPY_HW_MAX_I2C]; @@ -468,7 +473,7 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { #endif -#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop) { int ret; diff --git a/ports/stm32/led.c b/ports/stm32/led.c index adcb240cc..078327462 100644 --- a/ports/stm32/led.c +++ b/ports/stm32/led.c @@ -58,6 +58,12 @@ STATIC const pyb_led_obj_t pyb_led_obj[] = { {{&pyb_led_type}, 3, MICROPY_HW_LED3}, #if defined(MICROPY_HW_LED4) {{&pyb_led_type}, 4, MICROPY_HW_LED4}, + #if defined(MICROPY_HW_LED5) + {{&pyb_led_type}, 5, MICROPY_HW_LED5}, + #if defined(MICROPY_HW_LED6) + {{&pyb_led_type}, 6, MICROPY_HW_LED6}, + #endif + #endif #endif #endif #endif @@ -77,7 +83,9 @@ void led_init(void) { #if defined(MICROPY_HW_LED1_PWM) \ || defined(MICROPY_HW_LED2_PWM) \ || defined(MICROPY_HW_LED3_PWM) \ - || defined(MICROPY_HW_LED4_PWM) + || defined(MICROPY_HW_LED4_PWM) \ + || defined(MICROPY_HW_LED5_PWM) \ + || defined(MICROPY_HW_LED6_PWM) // The following is semi-generic code to control LEDs using PWM. // It currently supports TIM1, TIM2 and TIM3, channels 1-4. @@ -98,6 +106,12 @@ void led_init(void) { #ifndef MICROPY_HW_LED4_PWM #define MICROPY_HW_LED4_PWM { NULL, 0, 0, 0 } #endif +#ifndef MICROPY_HW_LED5_PWM +#define MICROPY_HW_LED5_PWM { NULL, 0, 0, 0 } +#endif +#ifndef MICROPY_HW_LED6_PWM +#define MICROPY_HW_LED6_PWM { NULL, 0, 0, 0 } +#endif #define LED_PWM_TIM_PERIOD (10000) // TIM runs at 1MHz and fires every 10ms @@ -116,6 +130,8 @@ STATIC const led_pwm_config_t led_pwm_config[] = { MICROPY_HW_LED2_PWM, MICROPY_HW_LED3_PWM, MICROPY_HW_LED4_PWM, + MICROPY_HW_LED5_PWM, + MICROPY_HW_LED6_PWM, }; STATIC uint8_t led_pwm_state = 0; diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c index f28bd5b39..8480bff53 100644 --- a/ports/stm32/machine_adc.c +++ b/ports/stm32/machine_adc.c @@ -34,10 +34,12 @@ #define ADC_V2 (0) #endif -#if defined(STM32F4) || defined(STM32L4) +#if defined(STM32F4) #define ADCx_COMMON ADC_COMMON_REGISTER(0) #elif defined(STM32F7) #define ADCx_COMMON ADC123_COMMON +#elif defined(STM32L4) +#define ADCx_COMMON __LL_ADC_COMMON_INSTANCE(0) #endif #if defined(STM32F0) || defined(STM32L0) @@ -130,6 +132,8 @@ void adc_config(ADC_TypeDef *adc, uint32_t bits) { 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(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + ADC12_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos; #elif defined(STM32H7) ADC12_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos; ADC3_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos; @@ -290,8 +294,9 @@ STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp *smpr = (*smpr & ~(7 << (channel * 3))) | sample_time << (channel * 3); // select sample time #elif defined(STM32H7) || defined(STM32L4) || defined(STM32WB) - - #if defined(STM32H7) + #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + ADC_Common_TypeDef *adc_common = ADC12_COMMON; + #elif defined(STM32H7) adc->PCSEL |= 1 << channel; ADC_Common_TypeDef *adc_common = adc == ADC3 ? ADC3_COMMON : ADC12_COMMON; #elif defined(STM32L4) @@ -413,7 +418,7 @@ STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, s } else if (pin->adc_num & PIN_ADC2) { adc = ADC2; #endif - #if defined(ADC2) + #if defined(ADC3) } else if (pin->adc_num & PIN_ADC3) { adc = ADC3; #endif diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 41e65cf05..0976c18c8 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -38,7 +38,7 @@ #define I2C_POLL_DEFAULT_TIMEOUT_US (50000) // 50ms -#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) typedef struct _machine_hard_i2c_obj_t { mp_obj_base_t base; diff --git a/ports/stm32/machine_i2s.c b/ports/stm32/machine_i2s.c index 32167cf4e..31b7d14bf 100644 --- a/ports/stm32/machine_i2s.c +++ b/ports/stm32/machine_i2s.c @@ -81,8 +81,6 @@ // 32 byte address boundary. Not all STM32 devices have a D-Cache. Buffer alignment // will still happen on these devices to keep this code simple. -#define MAX_I2S_STM32 (2) - // DMA ping-pong buffer size was empirically determined. It is a tradeoff between: // 1. memory use (smaller buffer size desirable to reduce memory footprint) // 2. interrupt frequency (larger buffer size desirable to reduce interrupt frequency) @@ -164,11 +162,9 @@ STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYT { 2, 3, 0, 1, 6, 7, 4, 5 }, // Stereo, 32-bits }; -STATIC machine_i2s_obj_t *machine_i2s_obj[MAX_I2S_STM32]; - void machine_i2s_init0() { - for (uint8_t i = 0; i < MAX_I2S_STM32; i++) { - machine_i2s_obj[i] = NULL; + for (uint8_t i = 0; i < MICROPY_HW_MAX_I2S; i++) { + MP_STATE_PORT(machine_i2s_obj)[i] = NULL; } } @@ -509,6 +505,9 @@ STATIC void feed_dma(machine_i2s_obj_t *self, ping_pong_t dma_ping_pong) { if (self->bits == 32) { reformat_32_bit_samples((int32_t *)dma_buffer_p, SIZEOF_HALF_DMA_BUFFER_IN_BYTES / (sizeof(uint32_t))); } + } else { + // underflow. clear buffer to transmit "silence" on the I2S bus + memset(dma_buffer_p, 0, SIZEOF_HALF_DMA_BUFFER_IN_BYTES); } // flush cache to RAM so DMA can read the sample data @@ -598,9 +597,9 @@ void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s) { void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) { machine_i2s_obj_t *self; if (hi2s->Instance == I2S1) { - self = machine_i2s_obj[0]; + self = MP_STATE_PORT(machine_i2s_obj)[0]; } else { - self = machine_i2s_obj[1]; + self = MP_STATE_PORT(machine_i2s_obj)[1]; } // bottom half of buffer now filled, @@ -617,9 +616,9 @@ void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) { void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) { machine_i2s_obj_t *self; if (hi2s->Instance == I2S1) { - self = machine_i2s_obj[0]; + self = MP_STATE_PORT(machine_i2s_obj)[0]; } else { - self = machine_i2s_obj[1]; + self = MP_STATE_PORT(machine_i2s_obj)[1]; } // top half of buffer now filled, @@ -637,9 +636,9 @@ void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) { machine_i2s_obj_t *self; if (hi2s->Instance == I2S1) { - self = machine_i2s_obj[0]; + self = MP_STATE_PORT(machine_i2s_obj)[0]; } else { - self = machine_i2s_obj[1]; + self = MP_STATE_PORT(machine_i2s_obj)[1]; } // for non-blocking operation, this IRQ-based callback handles @@ -656,9 +655,9 @@ void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) { void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) { machine_i2s_obj_t *self; if (hi2s->Instance == I2S1) { - self = machine_i2s_obj[0]; + self = MP_STATE_PORT(machine_i2s_obj)[0]; } else { - self = machine_i2s_obj[1]; + self = MP_STATE_PORT(machine_i2s_obj)[1]; } // for non-blocking operation, this IRQ-based callback handles @@ -856,13 +855,13 @@ STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_arg } machine_i2s_obj_t *self; - if (machine_i2s_obj[i2s_id_zero_base] == NULL) { + if (MP_STATE_PORT(machine_i2s_obj)[i2s_id_zero_base] == NULL) { self = m_new_obj(machine_i2s_obj_t); - machine_i2s_obj[i2s_id_zero_base] = self; + MP_STATE_PORT(machine_i2s_obj)[i2s_id_zero_base] = self; self->base.type = &machine_i2s_type; self->i2s_id = i2s_id; } else { - self = machine_i2s_obj[i2s_id_zero_base]; + self = MP_STATE_PORT(machine_i2s_obj)[i2s_id_zero_base]; machine_i2s_deinit(MP_OBJ_FROM_PTR(self)); } diff --git a/ports/stm32/main.c b/ports/stm32/main.c index d55f1a2c3..431fa20de 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -39,6 +39,7 @@ #include "lib/littlefs/lfs1_util.h" #include "lib/littlefs/lfs2.h" #include "lib/littlefs/lfs2_util.h" +#include "extmod/modnetwork.h" #include "extmod/vfs.h" #include "extmod/vfs_fat.h" #include "extmod/vfs_lfs.h" @@ -83,7 +84,6 @@ #include "servo.h" #include "dac.h" #include "can.h" -#include "modnetwork.h" #if MICROPY_PY_THREAD STATIC pyb_thread_t pyb_thread_main; @@ -369,14 +369,6 @@ void stm32_main(uint32_t reset_mode) { // set the system clock to be HSE SystemClock_Config(); - // enable GPIO clocks - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - #if defined(GPIOD) - __HAL_RCC_GPIOD_CLK_ENABLE(); - #endif - #if defined(STM32F4) || defined(STM32F7) #if defined(__HAL_RCC_DTCMRAMEN_CLK_ENABLE) // The STM32F746 doesn't really have CCM memory, but it does have DTCM, @@ -386,6 +378,9 @@ void stm32_main(uint32_t reset_mode) { // enable the CCM RAM __HAL_RCC_CCMDATARAMEN_CLK_ENABLE(); #endif + #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + // Enable SRAM clock. + __HAL_RCC_SRDSRAM_CLK_ENABLE(); #elif defined(STM32H7) // Enable D2 SRAM1/2/3 clocks. __HAL_RCC_D2SRAM1_CLK_ENABLE(); @@ -424,7 +419,7 @@ void stm32_main(uint32_t reset_mode) { #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C i2c_init0(); #endif - #if MICROPY_HW_ENABLE_SDCARD + #if MICROPY_HW_ENABLE_SDCARD || MICROPY_HW_ENABLE_MMCARD sdcard_init(); #endif #if MICROPY_HW_ENABLE_STORAGE @@ -499,9 +494,6 @@ soft_reset: // MicroPython init 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_)); // current dir (or base dir of the script) - mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); // Initialise low-level sub-systems. Here we need to very basic things like // zeroing out memory and resetting any of the sub-systems. Following this @@ -569,6 +561,11 @@ soft_reset: // reset config variables; they should be set by boot.py MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL; + // Run optional frozen boot code. + #ifdef MICROPY_BOARD_FROZEN_BOOT_FILE + pyexec_frozen_module(MICROPY_BOARD_FROZEN_BOOT_FILE); + #endif + // Run boot.py (or whatever else a board configures at this stage). if (MICROPY_BOARD_RUN_BOOT_PY(&state) == BOARDCTRL_GOTO_SOFT_RESET_EXIT) { goto soft_reset_exit; diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py index 602bdc6c1..217a801a8 100644 --- a/ports/stm32/make-stmconst.py +++ b/ports/stm32/make-stmconst.py @@ -17,7 +17,6 @@ if platform.python_version_tuple()[0] == "2": def convert_bytes_to_str(b): return b - elif platform.python_version_tuple()[0] == "3": def convert_bytes_to_str(b): diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c index 6c7d2c771..278c07fb4 100644 --- a/ports/stm32/mboot/main.c +++ b/ports/stm32/mboot/main.c @@ -501,6 +501,8 @@ void led0_update() { #define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT #elif defined(STM32H743xx) #define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/16*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT +#elif defined(STM32H750xx) +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/01*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT #elif defined(STM32WB) #define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/256*04Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT #endif diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c index 07178b65c..952e535c2 100644 --- a/ports/stm32/modnwcc3k.c +++ b/ports/stm32/modnwcc3k.c @@ -37,7 +37,7 @@ #include "py/mperrno.h" #include "py/mphal.h" #include "shared/netutils/netutils.h" -#include "modnetwork.h" +#include "extmod/modnetwork.h" #include "pin.h" #include "spi.h" @@ -136,13 +136,13 @@ STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uin } STATIC int cc3k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { - if (socket->u_param.domain != MOD_NETWORK_AF_INET) { + if (socket->domain != MOD_NETWORK_AF_INET) { *_errno = MP_EAFNOSUPPORT; return -1; } mp_uint_t type; - switch (socket->u_param.type) { + switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: type = SOCK_STREAM; break; @@ -168,23 +168,23 @@ STATIC int cc3k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { cc3k_reset_fd_closed_state(fd); // store state of this socket - socket->u_state = fd; + socket->fileno = fd; // make accept blocking by default int optval = SOCK_OFF; socklen_t optlen = sizeof(optval); - CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen); + CC3000_EXPORT(setsockopt)(socket->fileno, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen); return 0; } STATIC void cc3k_socket_close(mod_network_socket_obj_t *socket) { - CC3000_EXPORT(closesocket)(socket->u_state); + CC3000_EXPORT(closesocket)(socket->fileno); } STATIC int cc3k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { MAKE_SOCKADDR(addr, ip, port) - int ret = CC3000_EXPORT(bind)(socket->u_state, &addr, sizeof(addr)); + int ret = CC3000_EXPORT(bind)(socket->fileno, &addr, sizeof(addr)); if (ret != 0) { *_errno = ret; return -1; @@ -193,7 +193,7 @@ STATIC int cc3k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_ } STATIC int cc3k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) { - int ret = CC3000_EXPORT(listen)(socket->u_state, backlog); + int ret = CC3000_EXPORT(listen)(socket->fileno, backlog); if (ret != 0) { *_errno = ret; return -1; @@ -206,7 +206,7 @@ STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_sock int fd; sockaddr addr; socklen_t addr_len = sizeof(addr); - if ((fd = CC3000_EXPORT(accept)(socket->u_state, &addr, &addr_len)) < 0) { + if ((fd = CC3000_EXPORT(accept)(socket->fileno, &addr, &addr_len)) < 0) { if (fd == SOC_IN_PROGRESS) { *_errno = MP_EAGAIN; } else { @@ -219,7 +219,7 @@ STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_sock cc3k_reset_fd_closed_state(fd); // store state in new socket object - socket2->u_state = fd; + socket2->fileno = fd; // return ip and port // it seems CC3000 returns little endian for accept?? @@ -235,7 +235,7 @@ STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_sock STATIC int cc3k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { MAKE_SOCKADDR(addr, ip, port) - int ret = CC3000_EXPORT(connect)(socket->u_state, &addr, sizeof(addr)); + int ret = CC3000_EXPORT(connect)(socket->fileno, &addr, sizeof(addr)); if (ret != 0) { *_errno = CC3000_EXPORT(errno); return -1; @@ -244,8 +244,8 @@ STATIC int cc3k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_ui } STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { - if (cc3k_get_fd_closed_state(socket->u_state)) { - CC3000_EXPORT(closesocket)(socket->u_state); + if (cc3k_get_fd_closed_state(socket->fileno)) { + CC3000_EXPORT(closesocket)(socket->fileno); *_errno = MP_EPIPE; return -1; } @@ -255,7 +255,7 @@ STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte * mp_int_t bytes = 0; while (bytes < len) { int n = MIN((len - bytes), MAX_TX_PACKET); - n = CC3000_EXPORT(send)(socket->u_state, (uint8_t *)buf + bytes, n, 0); + n = CC3000_EXPORT(send)(socket->fileno, (uint8_t *)buf + bytes, n, 0); if (n <= 0) { *_errno = CC3000_EXPORT(errno); return -1; @@ -268,18 +268,18 @@ STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte * STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) { // check the socket is open - if (cc3k_get_fd_closed_state(socket->u_state)) { + if (cc3k_get_fd_closed_state(socket->fileno)) { // socket is closed, but CC3000 may have some data remaining in buffer, so check fd_set rfds; FD_ZERO(&rfds); - FD_SET(socket->u_state, &rfds); + FD_SET(socket->fileno, &rfds); cc3000_timeval tv; tv.tv_sec = 0; tv.tv_usec = 1; - int nfds = CC3000_EXPORT(select)(socket->u_state + 1, &rfds, NULL, NULL, &tv); - if (nfds == -1 || !FD_ISSET(socket->u_state, &rfds)) { + int nfds = CC3000_EXPORT(select)(socket->fileno + 1, &rfds, NULL, NULL, &tv); + if (nfds == -1 || !FD_ISSET(socket->fileno, &rfds)) { // no data waiting, so close socket and return 0 data - CC3000_EXPORT(closesocket)(socket->u_state); + CC3000_EXPORT(closesocket)(socket->fileno); return 0; } } @@ -288,7 +288,7 @@ STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, m len = MIN(len, MAX_RX_PACKET); // do the recv - int ret = CC3000_EXPORT(recv)(socket->u_state, buf, len, 0); + int ret = CC3000_EXPORT(recv)(socket->fileno, buf, len, 0); if (ret < 0) { *_errno = CC3000_EXPORT(errno); return -1; @@ -299,7 +299,7 @@ STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, m STATIC mp_uint_t cc3k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { MAKE_SOCKADDR(addr, ip, port) - int ret = CC3000_EXPORT(sendto)(socket->u_state, (byte *)buf, len, 0, (sockaddr *)&addr, sizeof(addr)); + int ret = CC3000_EXPORT(sendto)(socket->fileno, (byte *)buf, len, 0, (sockaddr *)&addr, sizeof(addr)); if (ret < 0) { *_errno = CC3000_EXPORT(errno); return -1; @@ -310,7 +310,7 @@ STATIC mp_uint_t cc3k_socket_sendto(mod_network_socket_obj_t *socket, const byte STATIC mp_uint_t cc3k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { sockaddr addr; socklen_t addr_len = sizeof(addr); - mp_int_t ret = CC3000_EXPORT(recvfrom)(socket->u_state, buf, len, 0, &addr, &addr_len); + mp_int_t ret = CC3000_EXPORT(recvfrom)(socket->fileno, buf, len, 0, &addr, &addr_len); if (ret < 0) { *_errno = CC3000_EXPORT(errno); return -1; @@ -320,7 +320,7 @@ STATIC mp_uint_t cc3k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *bu } STATIC int cc3k_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { - int ret = CC3000_EXPORT(setsockopt)(socket->u_state, level, opt, optval, optlen); + int ret = CC3000_EXPORT(setsockopt)(socket->fileno, level, opt, optval, optlen); if (ret < 0) { *_errno = CC3000_EXPORT(errno); return -1; @@ -340,14 +340,14 @@ STATIC int cc3k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t ti // set blocking mode optval = SOCK_OFF; } - ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, &optval, optlen); + ret = CC3000_EXPORT(setsockopt)(socket->fileno, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, &optval, optlen); if (ret == 0) { - ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen); + ret = CC3000_EXPORT(setsockopt)(socket->fileno, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen); } } else { // set timeout socklen_t optlen = sizeof(timeout_ms); - ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_TIMEOUT, &timeout_ms, optlen); + ret = CC3000_EXPORT(setsockopt)(socket->fileno, SOL_SOCKET, SOCKOPT_RECV_TIMEOUT, &timeout_ms, optlen); } if (ret != 0) { @@ -363,7 +363,7 @@ STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request if (request == MP_STREAM_POLL) { mp_uint_t flags = arg; ret = 0; - int fd = socket->u_state; + int fd = socket->fileno; // init fds fd_set rfds, wfds, xfds; diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c index 1e18d03ca..f7adad3f3 100644 --- a/ports/stm32/modnwwiznet5k.c +++ b/ports/stm32/modnwwiznet5k.c @@ -34,7 +34,7 @@ #include "py/mperrno.h" #include "py/mphal.h" #include "shared/netutils/netutils.h" -#include "modnetwork.h" +#include "extmod/modnetwork.h" #include "pin.h" #include "spi.h" @@ -99,33 +99,33 @@ STATIC int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, } STATIC int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { - if (socket->u_param.domain != MOD_NETWORK_AF_INET) { + if (socket->domain != MOD_NETWORK_AF_INET) { *_errno = MP_EAFNOSUPPORT; return -1; } - switch (socket->u_param.type) { + switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: - socket->u_param.type = Sn_MR_TCP; + socket->type = Sn_MR_TCP; break; case MOD_NETWORK_SOCK_DGRAM: - socket->u_param.type = Sn_MR_UDP; + socket->type = Sn_MR_UDP; break; default: *_errno = MP_EINVAL; return -1; } - if (socket->u_param.fileno == -1) { + if (socket->fileno == -1) { // get first unused socket number for (mp_uint_t sn = 0; sn < _WIZCHIP_SOCK_NUM_; sn++) { if ((wiznet5k_obj.socket_used & (1 << sn)) == 0) { wiznet5k_obj.socket_used |= (1 << sn); - socket->u_param.fileno = sn; + socket->fileno = sn; break; } } - if (socket->u_param.fileno == -1) { + if (socket->fileno == -1) { // too many open sockets *_errno = MP_EMFILE; return -1; @@ -137,13 +137,13 @@ STATIC int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) // So, we defer the open until we know what kind of socket we want. // use "domain" to indicate that this socket has not yet been opened - socket->u_param.domain = 0; + socket->domain = 0; return 0; } STATIC void wiznet5k_socket_close(mod_network_socket_obj_t *socket) { - uint8_t sn = (uint8_t)socket->u_param.fileno; + uint8_t sn = (uint8_t)socket->fileno; if (sn < _WIZCHIP_SOCK_NUM_) { wiznet5k_obj.socket_used &= ~(1 << sn); WIZCHIP_EXPORT(close)(sn); @@ -152,7 +152,7 @@ STATIC void wiznet5k_socket_close(mod_network_socket_obj_t *socket) { STATIC int wiznet5k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { // open the socket in server mode (if port != 0) - mp_int_t ret = WIZCHIP_EXPORT(socket)(socket->u_param.fileno, socket->u_param.type, port, 0); + mp_int_t ret = WIZCHIP_EXPORT(socket)(socket->fileno, socket->type, port, 0); if (ret < 0) { wiznet5k_socket_close(socket); *_errno = -ret; @@ -160,14 +160,14 @@ STATIC int wiznet5k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_u } // indicate that this socket has been opened - socket->u_param.domain = 1; + socket->domain = 1; // success return 0; } STATIC int wiznet5k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) { - mp_int_t ret = WIZCHIP_EXPORT(listen)(socket->u_param.fileno); + mp_int_t ret = WIZCHIP_EXPORT(listen)(socket->fileno); if (ret < 0) { wiznet5k_socket_close(socket); *_errno = -ret; @@ -178,17 +178,19 @@ STATIC int wiznet5k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t bac STATIC int wiznet5k_socket_accept(mod_network_socket_obj_t *socket, mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) { for (;;) { - int sr = getSn_SR((uint8_t)socket->u_param.fileno); + int sr = getSn_SR((uint8_t)socket->fileno); if (sr == SOCK_ESTABLISHED) { - socket2->u_param = socket->u_param; - getSn_DIPR((uint8_t)socket2->u_param.fileno, ip); - *port = getSn_PORT(socket2->u_param.fileno); + socket2->domain = socket->domain; + socket2->type = socket->type; + socket2->fileno = socket->fileno; + getSn_DIPR((uint8_t)socket2->fileno, ip); + *port = getSn_PORT(socket2->fileno); // WIZnet turns the listening socket into the client socket, so we // need to re-bind and re-listen on another socket for the server. // TODO handle errors, especially no-more-sockets error - socket->u_param.domain = MOD_NETWORK_AF_INET; - socket->u_param.fileno = -1; + socket->domain = MOD_NETWORK_AF_INET; + socket->fileno = -1; int _errno2; if (wiznet5k_socket_socket(socket, &_errno2) != 0) { // printf("(bad resocket %d)\n", _errno2); @@ -217,7 +219,7 @@ STATIC int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, m // now connect MP_THREAD_GIL_EXIT(); - mp_int_t ret = WIZCHIP_EXPORT(connect)(socket->u_param.fileno, ip, port); + mp_int_t ret = WIZCHIP_EXPORT(connect)(socket->fileno, ip, port); MP_THREAD_GIL_ENTER(); if (ret < 0) { @@ -232,7 +234,7 @@ STATIC int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, m STATIC mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { MP_THREAD_GIL_EXIT(); - mp_int_t ret = WIZCHIP_EXPORT(send)(socket->u_param.fileno, (byte *)buf, len); + mp_int_t ret = WIZCHIP_EXPORT(send)(socket->fileno, (byte *)buf, len); MP_THREAD_GIL_ENTER(); // TODO convert Wiz errno's to POSIX ones @@ -246,7 +248,7 @@ STATIC mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const by STATIC mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) { MP_THREAD_GIL_EXIT(); - mp_int_t ret = WIZCHIP_EXPORT(recv)(socket->u_param.fileno, buf, len); + mp_int_t ret = WIZCHIP_EXPORT(recv)(socket->fileno, buf, len); MP_THREAD_GIL_ENTER(); // TODO convert Wiz errno's to POSIX ones @@ -259,7 +261,7 @@ STATIC mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *bu } STATIC mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { - if (socket->u_param.domain == 0) { + if (socket->domain == 0) { // socket not opened; use "bind" function to open the socket in client mode if (wiznet5k_socket_bind(socket, ip, 0, _errno) != 0) { return -1; @@ -267,7 +269,7 @@ STATIC mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const } MP_THREAD_GIL_EXIT(); - mp_int_t ret = WIZCHIP_EXPORT(sendto)(socket->u_param.fileno, (byte *)buf, len, ip, port); + mp_int_t ret = WIZCHIP_EXPORT(sendto)(socket->fileno, (byte *)buf, len, ip, port); MP_THREAD_GIL_ENTER(); if (ret < 0) { @@ -281,7 +283,7 @@ STATIC mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const STATIC mp_uint_t wiznet5k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { uint16_t port2; MP_THREAD_GIL_EXIT(); - mp_int_t ret = WIZCHIP_EXPORT(recvfrom)(socket->u_param.fileno, buf, len, ip, &port2); + mp_int_t ret = WIZCHIP_EXPORT(recvfrom)(socket->fileno, buf, len, ip, &port2); MP_THREAD_GIL_ENTER(); *port = port2; if (ret < 0) { @@ -307,7 +309,7 @@ STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_ if (timeout_ms == 0) { // set non-blocking mode uint8_t arg = SOCK_IO_NONBLOCK; - WIZCHIP_EXPORT(ctlsocket)(socket->u_param.fileno, CS_SET_IOMODE, &arg); + WIZCHIP_EXPORT(ctlsocket)(socket->fileno, CS_SET_IOMODE, &arg); } */ } @@ -315,10 +317,10 @@ STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_ STATIC int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) { if (request == MP_STREAM_POLL) { int ret = 0; - if (arg & MP_STREAM_POLL_RD && getSn_RX_RSR(socket->u_param.fileno) != 0) { + if (arg & MP_STREAM_POLL_RD && getSn_RX_RSR(socket->fileno) != 0) { ret |= MP_STREAM_POLL_RD; } - if (arg & MP_STREAM_POLL_WR && getSn_TX_FSR(socket->u_param.fileno) != 0) { + if (arg & MP_STREAM_POLL_WR && getSn_TX_FSR(socket->fileno) != 0) { ret |= MP_STREAM_POLL_WR; } return ret; diff --git a/ports/stm32/mpbthciport.c b/ports/stm32/mpbthciport.c index 369c91e30..a1ab3258b 100644 --- a/ports/stm32/mpbthciport.c +++ b/ports/stm32/mpbthciport.c @@ -71,7 +71,7 @@ STATIC void mp_bluetooth_hci_start_polling(void) { mp_bluetooth_hci_poll_now(); } -void mp_bluetooth_hci_poll_in_ms(uint32_t ms) { +void mp_bluetooth_hci_poll_in_ms_default(uint32_t ms) { soft_timer_reinsert(&mp_bluetooth_hci_soft_timer, ms); } @@ -92,7 +92,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_sched // Called periodically (systick) or directly (e.g. UART RX IRQ) in order to // request that processing happens ASAP in the scheduler. -void mp_bluetooth_hci_poll_now(void) { +void mp_bluetooth_hci_poll_now_default(void) { if (!events_task_is_scheduled) { events_task_is_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&run_events_scheduled_task_obj), mp_const_none); if (!events_task_is_scheduled) { @@ -104,7 +104,7 @@ void mp_bluetooth_hci_poll_now(void) { #else // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS -void mp_bluetooth_hci_poll_now(void) { +void mp_bluetooth_hci_poll_now_default(void) { pendsv_schedule_dispatch(PENDSV_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll); } diff --git a/ports/stm32/mpbthciport.h b/ports/stm32/mpbthciport.h index 77919ee0e..d510ab52a 100644 --- a/ports/stm32/mpbthciport.h +++ b/ports/stm32/mpbthciport.h @@ -26,12 +26,24 @@ #ifndef MICROPY_INCLUDED_STM32_MPBTHCIPORT_H #define MICROPY_INCLUDED_STM32_MPBTHCIPORT_H +#include "boardctrl.h" + // Initialise the HCI subsystem (should be called once, early on). void mp_bluetooth_hci_init(void); -// Poll the HCI now, or after a certain timeout. -void mp_bluetooth_hci_poll_now(void); -void mp_bluetooth_hci_poll_in_ms(uint32_t ms); +// Default implementations of poll functions (a board can override them). +void mp_bluetooth_hci_poll_now_default(void); +void mp_bluetooth_hci_poll_in_ms_default(uint32_t ms); + +// Call this to poll the HCI now. +static inline void mp_bluetooth_hci_poll_now(void) { + MICROPY_BOARD_BT_HCI_POLL_NOW(); +} + +// Call this to poll the HCI after a certain timeout. +static inline void mp_bluetooth_hci_poll_in_ms(uint32_t ms) { + MICROPY_BOARD_BT_HCI_POLL_IN_MS(ms); +} // Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c). // Request new data from the uart and pass to the stack, and run pending events/callouts. diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 0cf6adce3..f8342f51b 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -57,6 +57,11 @@ #define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) #endif +// If internal flash storage is enabled, whether to use a second segment of flash. +#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE_SEGMENT2 (0) +#endif + // Whether to enable the RTC, exposed as pyb.RTC #ifndef MICROPY_HW_ENABLE_RTC #define MICROPY_HW_ENABLE_RTC (0) @@ -314,6 +319,17 @@ #define MICROPY_HW_MAX_UART (8) #define MICROPY_HW_MAX_LPUART (0) +// Configuration for STM32H7A3/B3 series +#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \ + defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x08fff800) +#define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_I2C (4) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (10) +#define MICROPY_HW_MAX_LPUART (1) + // Configuration for STM32H7 series #elif defined(STM32H7) @@ -479,6 +495,15 @@ #define MICROPY_HW_MAX_CAN (1) #endif +// Enable I2S if there are any peripherals defined +#if defined(MICROPY_HW_I2S1) || defined(MICROPY_HW_I2S2) +#define MICROPY_HW_ENABLE_I2S (1) +#define MICROPY_HW_MAX_I2S (2) +#else +#define MICROPY_HW_ENABLE_I2S (0) +#define MICROPY_HW_MAX_I2S (0) +#endif + // Define MICROPY_HW_SDMMCx_CK values if that peripheral is used, so that make-pins.py // generates the relevant AF constants. #if MICROPY_HW_SDCARD_SDMMC == 1 || MICROPY_HW_SDIO_SDMMC == 1 diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index b6b34e0a7..110e13c2b 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -31,6 +31,10 @@ #include "mpconfigboard.h" #include "mpconfigboard_common.h" +#ifndef MICROPY_CONFIG_ROM_LEVEL +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) +#endif + // memory allocation policies #ifndef MICROPY_GC_STACK_ENTRY_TYPE #if MICROPY_HW_SDRAM_SIZE @@ -41,6 +45,16 @@ #endif #define MICROPY_ALLOC_PATH_MAX (128) +// optimisations +#ifndef MICROPY_OPT_COMPUTED_GOTO +#define MICROPY_OPT_COMPUTED_GOTO (1) +#endif + +// Don't enable lookup cache on M0 (low RAM) +#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE +#define MICROPY_OPT_MAP_LOOKUP_CACHE (__CORTEX_M > 0) +#endif + // emitters #define MICROPY_PERSISTENT_CODE_LOAD (1) #ifndef MICROPY_EMIT_THUMB @@ -50,141 +64,43 @@ #define MICROPY_EMIT_INLINE_THUMB (1) #endif -// compiler configuration -#define MICROPY_COMP_MODULE_CONST (1) -#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) -#define MICROPY_COMP_RETURN_IF_EXPR (1) - -// optimisations -#ifndef MICROPY_OPT_COMPUTED_GOTO -#define MICROPY_OPT_COMPUTED_GOTO (1) -#endif -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) -#define MICROPY_OPT_MPZ_BITWISE (1) -#define MICROPY_OPT_MATH_FACTORIAL (1) - // Python internal features #define MICROPY_READER_VFS (1) #define MICROPY_ENABLE_GC (1) -#define MICROPY_ENABLE_FINALISER (1) -#define MICROPY_STACK_CHECK (1) #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) #define MICROPY_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) -#define MICROPY_ENABLE_SOURCE_LINE (1) #ifndef MICROPY_FLOAT_IMPL // can be configured by each board via mpconfigboard.mk #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #endif -#define MICROPY_STREAMS_NON_BLOCK (1) -#define MICROPY_MODULE_BUILTIN_INIT (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 (8) #define MICROPY_VFS (1) // control over Python builtins -#define MICROPY_PY_FUNCTION_ATTRS (1) -#define MICROPY_PY_DESCRIPTORS (1) -#define MICROPY_PY_DELATTR_SETATTR (1) -#ifndef MICROPY_PY_FSTRINGS -#define MICROPY_PY_FSTRINGS (1) -#endif -#define MICROPY_PY_BUILTINS_STR_UNICODE (1) -#define MICROPY_PY_BUILTINS_STR_CENTER (1) -#define MICROPY_PY_BUILTINS_STR_PARTITION (1) -#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) -#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) -#define MICROPY_PY_BUILTINS_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_REVERSE_SPECIAL_METHODS (1) -#define MICROPY_PY_BUILTINS_COMPILE (MICROPY_ENABLE_COMPILER) -#define MICROPY_PY_BUILTINS_EXECFILE (MICROPY_ENABLE_COMPILER) -#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) -#define MICROPY_PY_BUILTINS_INPUT (1) -#define MICROPY_PY_BUILTINS_POW3 (1) -#define MICROPY_PY_BUILTINS_HELP (1) #ifndef MICROPY_PY_BUILTINS_HELP_TEXT #define MICROPY_PY_BUILTINS_HELP_TEXT stm32_help_text #endif -#define MICROPY_PY_BUILTINS_HELP_MODULES (1) -#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) -#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) -#define MICROPY_PY_COLLECTIONS_DEQUE (1) -#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) -#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) -#define MICROPY_PY_MATH_ISCLOSE (1) -#define MICROPY_PY_MATH_FACTORIAL (1) -#define MICROPY_PY_CMATH (1) -#define MICROPY_PY_IO (1) -#define MICROPY_PY_IO_IOBASE (1) #define MICROPY_PY_IO_FILEIO (MICROPY_VFS_FAT || MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2) -#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) #ifndef MICROPY_PY_SYS_PLATFORM // let boards override it if they want #define MICROPY_PY_SYS_PLATFORM "pyboard" #endif -#define MICROPY_PY_UERRNO (1) #ifndef MICROPY_PY_THREAD #define MICROPY_PY_THREAD (1) #endif // extended modules -#ifndef MICROPY_PY_UASYNCIO -#define MICROPY_PY_UASYNCIO (1) -#endif -#ifndef MICROPY_PY_UCTYPES -#define MICROPY_PY_UCTYPES (1) -#endif -#ifndef MICROPY_PY_UZLIB -#define MICROPY_PY_UZLIB (1) -#endif -#ifndef MICROPY_PY_UJSON -#define MICROPY_PY_UJSON (1) -#endif -#ifndef MICROPY_PY_URE -#define MICROPY_PY_URE (1) -#endif -#ifndef MICROPY_PY_URE_SUB -#define MICROPY_PY_URE_SUB (1) -#endif -#ifndef MICROPY_PY_UHEAPQ -#define MICROPY_PY_UHEAPQ (1) -#endif -#ifndef MICROPY_PY_UHASHLIB -#define MICROPY_PY_UHASHLIB (1) -#endif +#define MICROPY_PY_USSL_FINALISER (MICROPY_PY_USSL) #define MICROPY_PY_UHASHLIB_MD5 (MICROPY_PY_USSL) #define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL) #define MICROPY_PY_UCRYPTOLIB (MICROPY_PY_USSL) -#ifndef MICROPY_PY_UBINASCII -#define MICROPY_PY_UBINASCII (1) -#define MICROPY_PY_UBINASCII_CRC32 (1) -#endif #ifndef MICROPY_PY_UOS #define MICROPY_PY_UOS (1) #endif #define MICROPY_PY_OS_DUPTERM (3) #define MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM (1) -#ifndef MICROPY_PY_URANDOM -#define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URANDOM_SEED_INIT_FUNC (rng_get()) -#endif -#ifndef MICROPY_PY_URANDOM_EXTRA_FUNCS -#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) -#endif -#define MICROPY_PY_USELECT (1) #ifndef MICROPY_PY_UTIME #define MICROPY_PY_UTIME (1) #endif @@ -201,17 +117,16 @@ #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SOFTI2C (1) #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (SPI_FIRSTBIT_MSB) #define MICROPY_PY_MACHINE_SPI_LSB (SPI_FIRSTBIT_LSB) +#define MICROPY_PY_MACHINE_SOFTSPI (1) #endif #define MICROPY_HW_SOFTSPI_MIN_DELAY (0) #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) #define MICROPY_PY_UWEBSOCKET (MICROPY_PY_LWIP) #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 @@ -231,6 +146,9 @@ #ifndef MICROPY_PY_ONEWIRE #define MICROPY_PY_ONEWIRE (1) #endif +#ifndef MICROPY_PY_UPLATFORM +#define MICROPY_PY_UPLATFORM (1) +#endif // fatfs configuration used in ffconf.h #define MICROPY_FATFS_ENABLE_LFN (1) @@ -347,6 +265,38 @@ extern const struct _mp_obj_module_t mp_module_lodepng; #define ONEWIRE_BUILTIN_MODULE #endif +#if defined(MICROPY_HW_ETH_MDC) +extern const struct _mp_obj_type_t network_lan_type; +#define MICROPY_HW_NIC_ETH { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) }, +#else +#define MICROPY_HW_NIC_ETH +#endif + +#if MICROPY_PY_NETWORK_CYW43 +extern const struct _mp_obj_type_t mp_network_cyw43_type; +#define MICROPY_HW_NIC_CYW43 { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) }, +#else +#define MICROPY_HW_NIC_CYW43 +#endif + +#if MICROPY_PY_WIZNET5K +#if MICROPY_PY_LWIP +extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k; +#else +extern const struct _mod_network_nic_type_t mod_network_nic_type_wiznet5k; +#endif +#define MICROPY_HW_NIC_WIZNET5K { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) }, +#else +#define MICROPY_HW_NIC_WIZNET5K +#endif + +#if MICROPY_PY_CC3K +extern const struct _mod_network_nic_type_t mod_network_nic_type_cc3k; +#define MICROPY_HW_NIC_CC3K { MP_ROM_QSTR(MP_QSTR_CC3K), MP_ROM_PTR(&mod_network_nic_type_cc3k) }, +#else +#define MICROPY_HW_NIC_CC3K +#endif + #define MICROPY_PORT_BUILTIN_MODULES \ MACHINE_BUILTIN_MODULE \ PYB_BUILTIN_MODULE \ @@ -366,6 +316,12 @@ extern const struct _mp_obj_module_t mp_module_lodepng; PYB_BUILTIN_MODULE \ STM_BUILTIN_MODULE \ +#define MICROPY_PORT_NETWORK_INTERFACES \ + MICROPY_HW_NIC_ETH \ + MICROPY_HW_NIC_CYW43 \ + MICROPY_HW_NIC_WIZNET5K \ + MICROPY_HW_NIC_CC3K \ + #define MP_STATE_PORT MP_STATE_VM #if MICROPY_PY_LVGL @@ -440,6 +396,9 @@ struct _mp_bluetooth_btstack_root_pointers_t; /* pointers to all CAN objects (if they have been created) */ \ struct _pyb_can_obj_t *pyb_can_obj_all[MICROPY_HW_MAX_CAN]; \ \ + /* pointers to all I2S objects (if they have been created) */ \ + struct _machine_i2s_obj_t *machine_i2s_obj[MICROPY_HW_MAX_I2S]; \ + \ /* USB_VCP IRQ callbacks (if they have been set) */ \ mp_obj_t pyb_usb_vcp_irq[MICROPY_HW_USB_CDC_NUM]; \ \ diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index a76945db5..6cfa9b927 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -2,6 +2,27 @@ #include STM32_HAL_H #include "pin.h" +// F0-1.9.0+F4-1.16.0+F7-1.7.0+G4-1.3.0+H7-1.6.0+L0-1.11.2+L4-1.17.0+WB-1.10.0+WL-1.1.0 +#if defined(STM32F0) +#define MICROPY_PLATFORM_VERSION "HAL1.9.0" +#elif defined(STM32F4) +#define MICROPY_PLATFORM_VERSION "HAL1.16.0" +#elif defined(STM32F7) +#define MICROPY_PLATFORM_VERSION "HAL1.7.0" +#elif defined(STM32G4) +#define MICROPY_PLATFORM_VERSION "HAL1.3.0" +#elif defined(STM32H7) +#define MICROPY_PLATFORM_VERSION "HAL1.6.0" +#elif defined(STM32L0) +#define MICROPY_PLATFORM_VERSION "HAL1.11.2" +#elif defined(STM32L4) +#define MICROPY_PLATFORM_VERSION "HAL1.17.0" +#elif defined(STM32WB) +#define MICROPY_PLATFORM_VERSION "HAL1.10.0" +#elif defined(STM32WL) +#define MICROPY_PLATFORM_VERSION "HAL1.1.0" +#endif + extern const unsigned char mp_hal_status_to_errno_table[4]; static inline int mp_hal_status_to_neg_errno(HAL_StatusTypeDef status) { diff --git a/ports/stm32/mpnetworkport.c b/ports/stm32/mpnetworkport.c new file mode 100644 index 000000000..c879c5005 --- /dev/null +++ b/ports/stm32/mpnetworkport.c @@ -0,0 +1,85 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "shared/netutils/netutils.h" +#include "systick.h" +#include "pendsv.h" +#include "extmod/modnetwork.h" + +#if MICROPY_PY_LWIP +#include "lwip/netif.h" +#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" + +// Poll lwIP every 128ms +#define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) + +#if MICROPY_PY_WIZNET5K +void wiznet5k_poll(void); +#endif + +u32_t sys_now(void) { + return mp_hal_ticks_ms(); +} + +STATIC void pyb_lwip_poll(void) { + #if MICROPY_PY_WIZNET5K + // Poll the NIC for incoming data + wiznet5k_poll(); + #endif + + // Run the lwIP internal updates + 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); + } + + #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 // MICROPY_PY_LWIP diff --git a/ports/stm32/network_lan.c b/ports/stm32/network_lan.c index 6dd9aadb6..f19916a1d 100644 --- a/ports/stm32/network_lan.c +++ b/ports/stm32/network_lan.c @@ -26,7 +26,7 @@ #include "py/runtime.h" #include "py/mphal.h" -#include "modnetwork.h" +#include "extmod/modnetwork.h" #include "eth.h" #if defined(MICROPY_HW_ETH_MDC) diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c index bd4c02cb0..a52919155 100644 --- a/ports/stm32/network_wiznet5k.c +++ b/ports/stm32/network_wiznet5k.c @@ -29,8 +29,8 @@ #include "py/runtime.h" #include "py/mphal.h" +#include "extmod/modnetwork.h" #include "spi.h" -#include "modnetwork.h" #if MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP @@ -269,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.type == &mod_network_nic_type_wiznet5k) { + if (wiznet5k_obj.base.type == (mp_obj_type_t *)&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(); @@ -277,7 +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.type = &mod_network_nic_type_wiznet5k; + wiznet5k_obj.base.type = (mp_obj_type_t *)&mod_network_nic_type_wiznet5k; wiznet5k_obj.cris_state = 0; wiznet5k_obj.spi = spi; wiznet5k_obj.cs = cs; diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index aa8f90e3e..0733d355d 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_STM32_PENDSV_H #define MICROPY_INCLUDED_STM32_PENDSV_H +#include "boardctrl.h" + enum { PENDSV_DISPATCH_SOFT_TIMER, #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP @@ -37,6 +39,7 @@ enum { #if MICROPY_PY_BLUETOOTH && !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS PENDSV_DISPATCH_BLUETOOTH_HCI, #endif + MICROPY_BOARD_PENDSV_ENTRIES PENDSV_DISPATCH_MAX }; diff --git a/ports/stm32/pin.c b/ports/stm32/pin.c index f1c5eee85..ad153311e 100644 --- a/ports/stm32/pin.c +++ b/ports/stm32/pin.c @@ -256,6 +256,9 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } else { + // enable the peripheral clock so pin reading at least works + mp_hal_gpio_clock_enable(pin->gpio); } return MP_OBJ_FROM_PTR(pin); diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 137312ade..406325581 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -32,18 +32,26 @@ #if defined(STM32H7) #define RCC_SR RSR -#if defined(STM32H743xx) +#if defined(STM32H743xx) || defined(STM32H750xx) #define RCC_SR_SFTRSTF RCC_RSR_SFTRSTF #elif defined(STM32H747xx) #define RCC_SR_SFTRSTF RCC_RSR_SFT2RSTF +#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) +#define RCC_SR_SFTRSTF RCC_RSR_SFTRSTF #endif #define RCC_SR_RMVF RCC_RSR_RMVF // This macro returns the actual voltage scaling level factoring in the power overdrive bit. // If the current voltage scale is VOLTAGE_SCALE1 and PWER_ODEN bit is set return VOLTAGE_SCALE0 // otherwise the current voltage scaling (level VOS1 to VOS3) set in PWER_CSR is returned instead. +#if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \ + defined(STM32H7B3xx) || defined(STM32H7B3xxQ) +// TODO +#define POWERCTRL_GET_VOLTAGE_SCALING() PWR_REGULATOR_VOLTAGE_SCALE0 +#else #define POWERCTRL_GET_VOLTAGE_SCALING() \ (((PWR->CSR1 & PWR_CSR1_ACTVOS) && (SYSCFG->PWRCR & SYSCFG_PWRCR_ODEN)) ? \ PWR_REGULATOR_VOLTAGE_SCALE0 : (PWR->CSR1 & PWR_CSR1_ACTVOS)) +#endif #else #define RCC_SR CSR #define RCC_SR_SFTRSTF RCC_CSR_SFTRSTF @@ -148,6 +156,15 @@ STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = { { 180, PWR_REGULATOR_VOLTAGE_SCALE2 }, // Above 180MHz uses default PWR_REGULATOR_VOLTAGE_SCALE1 }; +#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \ + defined(STM32H7B3xx) || defined(STM32H7B3xxQ) +STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = { + // See table 15 "FLASH recommended number of wait states and programming delay" of RM0455. + {88, PWR_REGULATOR_VOLTAGE_SCALE3}, + {160, PWR_REGULATOR_VOLTAGE_SCALE2}, + {225, PWR_REGULATOR_VOLTAGE_SCALE1}, + {280, PWR_REGULATOR_VOLTAGE_SCALE0}, +}; #elif defined(STM32H7) STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = { // See table 55 "Kernel clock distribution overview" of RM0433. @@ -836,6 +853,9 @@ void powerctrl_enter_standby_mode(void) { #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) + #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE) + #define SR_BITS (RTC_SR_ALRAF | RTC_SR_ALRBF | RTC_SR_WUTF | RTC_SR_TSF) #else #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE) #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF) @@ -852,7 +872,11 @@ void powerctrl_enter_standby_mode(void) { RTC->CR &= ~CR_BITS; // clear RTC wake-up flags + #if defined(SR_BITS) + RTC->SR &= ~SR_BITS; + #else RTC->ISR &= ~ISR_BITS; + #endif #if defined(STM32F7) // Save EWUP state diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c index b82d3d81c..5ead66f4e 100644 --- a/ports/stm32/qspi.c +++ b/ports/stm32/qspi.c @@ -318,7 +318,7 @@ STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, ; QUADSPI->ABR = 0; // alternate byte: disable continuous read mode - QUADSPI->AR = addr; // addres to read from + QUADSPI->AR = addr; // address to read from // Read in the data 4 bytes at a time if dest is aligned if (((uintptr_t)dest & 3) == 0) { diff --git a/ports/stm32/qstrdefsport.h b/ports/stm32/qstrdefsport.h index bc07f2752..e7d84cbec 100644 --- a/ports/stm32/qstrdefsport.h +++ b/ports/stm32/qstrdefsport.h @@ -38,7 +38,19 @@ Q(/) #if MICROPY_HW_ENABLE_USB // for usb modes -Q(MSC+HID) +Q(VCP) +Q(MSC) Q(VCP+MSC) Q(VCP+HID) +Q(VCP+MSC+HID) +#if MICROPY_HW_USB_CDC_NUM >= 2 +Q(2xVCP) +Q(2xVCP+MSC) +Q(2xVCP+MSC+HID) +#endif +#if MICROPY_HW_USB_CDC_NUM >= 3 +Q(3xVCP) +Q(3xVCP+MSC) +Q(3xVCP+MSC+HID) +#endif #endif diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index ab8b49e18..a5553b8a0 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -339,9 +339,15 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) { hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16); // Exit Initialization mode + #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + hrtc->Instance->ICSR &= (uint32_t) ~RTC_ICSR_INIT; + #else hrtc->Instance->ISR &= (uint32_t) ~RTC_ISR_INIT; + #endif - #if defined(STM32L0) || defined(STM32L4) || defined(STM32H7) || defined(STM32WB) + #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + // do nothing + #elif 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) @@ -693,8 +699,13 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { RTC->CR &= ~RTC_CR_WUTE; // wait until WUTWF is set + #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + while (!(RTC->ICSR & RTC_ICSR_WUTWF)) { + } + #else while (!(RTC->ISR & RTC_ISR_WUTWF)) { } + #endif if (enable) { // program WUT @@ -721,7 +732,11 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { #endif // clear interrupt flags + #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + RTC->SR &= ~RTC_SR_WUTF; + #else RTC->ISR &= ~RTC_ISR_WUTF; + #endif #if defined(STM32L4) || defined(STM32WB) EXTI->PR1 = 1 << EXTI_RTC_WAKEUP; #elif defined(STM32H7) diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index ea69e7285..cb773f29d 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -60,6 +60,10 @@ #define STATIC_AF_SDCARD_D1 STATIC_AF_SDMMC2_D1 #define STATIC_AF_SDCARD_D2 STATIC_AF_SDMMC2_D2 #define STATIC_AF_SDCARD_D3 STATIC_AF_SDMMC2_D3 +#define STATIC_AF_SDCARD_D4 STATIC_AF_SDMMC2_D4 +#define STATIC_AF_SDCARD_D5 STATIC_AF_SDMMC2_D5 +#define STATIC_AF_SDCARD_D6 STATIC_AF_SDMMC2_D6 +#define STATIC_AF_SDCARD_D7 STATIC_AF_SDMMC2_D7 #else #define SDIO SDMMC1 #define SDMMC_IRQHandler SDMMC1_IRQHandler @@ -75,6 +79,10 @@ #define STATIC_AF_SDCARD_D1 STATIC_AF_SDMMC1_D1 #define STATIC_AF_SDCARD_D2 STATIC_AF_SDMMC1_D2 #define STATIC_AF_SDCARD_D3 STATIC_AF_SDMMC1_D3 +#define STATIC_AF_SDCARD_D4 STATIC_AF_SDMMC1_D4 +#define STATIC_AF_SDCARD_D5 STATIC_AF_SDMMC1_D5 +#define STATIC_AF_SDCARD_D6 STATIC_AF_SDMMC1_D6 +#define STATIC_AF_SDCARD_D7 STATIC_AF_SDMMC1_D7 #endif // The F7 & L4 series calls the peripheral SDMMC rather than SDIO, so provide some @@ -120,6 +128,10 @@ #define STATIC_AF_SDCARD_D1 STATIC_AF_SDIO_D1 #define STATIC_AF_SDCARD_D2 STATIC_AF_SDIO_D2 #define STATIC_AF_SDCARD_D3 STATIC_AF_SDIO_D3 +#define STATIC_AF_SDCARD_D4 STATIC_AF_SDIO_D4 +#define STATIC_AF_SDCARD_D5 STATIC_AF_SDIO_D5 +#define STATIC_AF_SDCARD_D6 STATIC_AF_SDIO_D6 +#define STATIC_AF_SDCARD_D7 STATIC_AF_SDIO_D7 #endif @@ -133,6 +145,13 @@ #define MICROPY_HW_SDCARD_CMD (pin_D2) #endif +// Define a constant to select the bus width. +#if MICROPY_HW_SDCARD_BUS_WIDTH == 4 +#define SDIO_BUS_WIDE_VALUE SDIO_BUS_WIDE_4B +#elif MICROPY_HW_SDCARD_BUS_WIDTH == 8 +#define SDIO_BUS_WIDE_VALUE SDIO_BUS_WIDE_8B +#endif + #define PYB_SDMMC_FLAG_SD (0x01) #define PYB_SDMMC_FLAG_MMC (0x02) #define PYB_SDMMC_FLAG_ACTIVE (0x04) @@ -162,10 +181,16 @@ void sdcard_init(void) { mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_CK); mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_CMD); mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D0); - #if MICROPY_HW_SDCARD_BUS_WIDTH == 4 + #if MICROPY_HW_SDCARD_BUS_WIDTH >= 4 mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D1); mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D2); mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D3); + #if MICROPY_HW_SDCARD_BUS_WIDTH == 8 + mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D4, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D4); + mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D5, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D5); + mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D6, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D6); + mp_hal_pin_config_alt_static(MICROPY_HW_SDCARD_D7, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_SDCARD_D7); + #endif #endif // configure the SD card detect pin @@ -252,9 +277,9 @@ STATIC HAL_StatusTypeDef sdmmc_init_sd(void) { mp_hal_delay_ms(50); } - #if MICROPY_HW_SDCARD_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 MICROPY_HW_SDCARD_BUS_WIDTH >= 4 + // configure the SD bus width for 4/8-bit wide operation + status = HAL_SD_ConfigWideBusOperation(&sdmmc_handle.sd, SDIO_BUS_WIDE_VALUE); if (status != HAL_OK) { HAL_SD_DeInit(&sdmmc_handle.sd); return status; @@ -284,15 +309,19 @@ STATIC HAL_StatusTypeDef sdmmc_init_mmc(void) { return status; } - // As this is an eMMC card, overwrite LogBlockNbr with actual value - sdmmc_handle.mmc.MmcCard.LogBlockNbr = 7469056 + 2048; + #ifdef MICROPY_HW_MMCARD_LOG_BLOCK_NBR + // A board can override the number of logical blocks (card capacity) if needed. + // This is needed when a card is high capacity because the extended CSD command + // is not supported by the current version of the HAL. + sdmmc_handle.mmc.MmcCard.LogBlockNbr = MICROPY_HW_MMCARD_LOG_BLOCK_NBR; + #endif - #if MICROPY_HW_SDCARD_BUS_WIDTH == 4 - // Configure the SDIO bus width for 4-bit wide operation + #if MICROPY_HW_SDCARD_BUS_WIDTH >= 4 + // Configure the SDIO bus width for 4/8-bit 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); + status = HAL_MMC_ConfigWideBusOperation(&sdmmc_handle.mmc, SDIO_BUS_WIDE_VALUE); if (status != HAL_OK) { HAL_MMC_DeInit(&sdmmc_handle.mmc); return status; diff --git a/ports/stm32/sdio.c b/ports/stm32/sdio.c index 3fb84a4d8..bedafcb13 100644 --- a/ports/stm32/sdio.c +++ b/ports/stm32/sdio.c @@ -134,9 +134,6 @@ void sdio_init(uint32_t irq_pri) { void sdio_deinit(void) { SDMMC_CLK_DISABLE(); - #if defined(STM32F7) - __HAL_RCC_DMA2_CLK_DISABLE(); - #endif } void sdio_reenable(void) { diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c index e0e350083..4615c4fe1 100644 --- a/ports/stm32/sdram.c +++ b/ports/stm32/sdram.c @@ -283,10 +283,10 @@ void sdram_leave_low_power(void) { #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif -bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) { +bool __attribute__((optimize("Os"))) sdram_test(bool exhaustive) { uint8_t const pattern = 0xaa; uint8_t const antipattern = 0x55; - uint8_t *const mem_base = (uint8_t *)sdram_start(); + volatile uint8_t *const mem_base = (uint8_t *)sdram_start(); #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR char error_buffer[1024]; @@ -310,12 +310,13 @@ bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) { // Test data bus for (uint32_t i = 0; i < MICROPY_HW_SDRAM_MEM_BUS_WIDTH; i++) { - *((uint32_t *)mem_base) = (1 << i); - if (*((uint32_t *)mem_base) != (1 << i)) { + *((volatile uint32_t *)mem_base) = (1 << i); + __DSB(); + if (*((volatile uint32_t *)mem_base) != (1 << i)) { #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR snprintf(error_buffer, sizeof(error_buffer), "Data bus test failed at 0x%p expected 0x%x found 0x%lx", - &mem_base[0], (1 << i), ((uint32_t *)mem_base)[0]); + &mem_base[0], (1 << i), ((volatile uint32_t *)mem_base)[0]); __fatal_error(error_buffer); #endif return false; @@ -325,6 +326,7 @@ bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) { // Test address bus for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) { mem_base[i] = pattern; + __DSB(); if (mem_base[i] != pattern) { #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR snprintf(error_buffer, sizeof(error_buffer), @@ -338,6 +340,7 @@ bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) { // Check for aliasing (overlaping addresses) mem_base[0] = antipattern; + __DSB(); for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) { if (mem_base[i] != pattern) { #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR @@ -356,15 +359,15 @@ bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) { // is enabled, it's not just writing and reading from cache. // Note: This test should also detect refresh rate issues. for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; i++) { - mem_base[i] = pattern; + mem_base[i] = ((i % 2) ? pattern : antipattern); } for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; i++) { - if (mem_base[i] != pattern) { + if (mem_base[i] != ((i % 2) ? pattern : antipattern)) { #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR snprintf(error_buffer, sizeof(error_buffer), "Address bus slow test failed at 0x%p expected 0x%x found 0x%x", - &mem_base[i], pattern, mem_base[i]); + &mem_base[i], ((i % 2) ? pattern : antipattern), mem_base[i]); __fatal_error(error_buffer); #endif return false; diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index fcd5b034a..f07e33715 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -395,7 +395,9 @@ void OTG_FS_WKUP_IRQHandler(void) { OTG_CMD_WKUP_Handler(&pcd_fs_handle); - #if !defined(STM32H7) + #if defined(STM32L4) + EXTI->PR1 = USB_OTG_FS_WAKEUP_EXTI_LINE; + #elif !defined(STM32H7) /* Clear EXTI pending Bit*/ __HAL_USB_FS_EXTI_CLEAR_FLAG(); #endif @@ -527,7 +529,11 @@ void TAMP_STAMP_IRQHandler(void) { void RTC_WKUP_IRQHandler(void) { IRQ_ENTER(RTC_WKUP_IRQn); + #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + RTC->SR &= ~RTC_SR_WUTF; // clear wakeup interrupt flag + #else RTC->ISR &= ~RTC_ISR_WUTF; // clear wakeup interrupt flag + #endif Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback IRQ_EXIT(RTC_WKUP_IRQn); } diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index 4e89204bf..8142fd0a5 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -180,7 +180,9 @@ void SystemClock_Config(void) { #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) /* Enable Power Control clock */ - #if defined(STM32H7) + #if defined(STM32H7A3xxQ) || defined(STM32H7B3xxQ) + MODIFY_REG(PWR->CR3, PWR_SUPPLY_CONFIG_MASK, PWR_CR3_SMPSEN); + #elif defined(STM32H7) MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0); #else __PWR_CLK_ENABLE(); @@ -197,7 +199,7 @@ void SystemClock_Config(void) { #if defined(STM32H7) // Wait for PWR_FLAG_VOSRDY - while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) { + while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) { } #endif diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index a34d2984d..c23e7e02d 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -239,6 +239,9 @@ uint32_t timer_get_source_freq(uint32_t tim_id) { #if defined(STM32F0) source = HAL_RCC_GetPCLK1Freq(); clk_div = RCC->CFGR & RCC_CFGR_PPRE; + #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + source = HAL_RCC_GetPCLK2Freq(); + clk_div = RCC->CDCFGR2 & RCC_CDCFGR2_CDPPRE2; #elif defined(STM32H7) source = HAL_RCC_GetPCLK2Freq(); clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE2; @@ -251,6 +254,8 @@ uint32_t timer_get_source_freq(uint32_t tim_id) { source = HAL_RCC_GetPCLK1Freq(); #if defined(STM32F0) clk_div = RCC->CFGR & RCC_CFGR_PPRE; + #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + clk_div = RCC->CDCFGR1 & RCC_CDCFGR2_CDPPRE1; #elif defined(STM32H7) clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE1; #else diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index d2953b264..2c08257f3 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -40,11 +40,13 @@ #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 +#if defined(STM32H7) +#define USART_ISR_RXNE USART_ISR_RXNE_RXFNE +#endif #define UART_RXNE_IS_SET(uart) ((uart)->ISR & USART_ISR_RXNE) #endif + #define UART_RXNE_IT_EN(uart) do { (uart)->CR1 |= USART_CR1_RXNEIE; } while (0) #define UART_RXNE_IT_DIS(uart) do { (uart)->CR1 &= ~USART_CR1_RXNEIE; } while (0) @@ -717,6 +719,33 @@ uint32_t uart_get_source_freq(pyb_uart_obj_t *self) { uart_clk = LSE_VALUE; break; } + #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + uint32_t csel; + if (self->uart_id == 1 || self->uart_id == 6 || self->uart_id == 9 || self->uart_id == 10) { + csel = RCC->CDCCIP2R >> 3; + } else { + csel = RCC->CDCCIP2R; + } + switch (csel & 3) { + case 0: + if (self->uart_id == 1 || self->uart_id == 6 || self->uart_id == 9 || self->uart_id == 10) { + uart_clk = HAL_RCC_GetPCLK2Freq(); + } else { + uart_clk = HAL_RCC_GetPCLK1Freq(); + } + break; + case 3: + uart_clk = HSI_VALUE; + break; + case 4: + uart_clk = CSI_VALUE; + break; + case 5: + uart_clk = LSE_VALUE; + break; + default: + break; + } #elif defined(STM32H7) uint32_t csel; if (self->uart_id == 1 || self->uart_id == 6) { @@ -850,7 +879,17 @@ int uart_rx_char(pyb_uart_obj_t *self) { self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set return data; #else - return self->uartx->DR & self->char_mask; + int data = self->uartx->DR & self->char_mask; + // Re-enable any IRQs that were disabled in uart_irq_handler because SR couldn't + // be cleared there (clearing SR in uart_irq_handler required reading DR which + // may have lost a character). + if (self->mp_irq_trigger & UART_FLAG_RXNE) { + self->uartx->CR1 |= USART_CR1_RXNEIE; + } + if (self->mp_irq_trigger & UART_FLAG_IDLE) { + self->uartx->CR1 |= USART_CR1_IDLEIE; + } + return data; #endif } } @@ -955,7 +994,10 @@ void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) { uart_tx_data(uart_obj, str, len, &errcode); } -// this IRQ handler is set up to handle RXNE interrupts only +// This IRQ handler is set up to handle RXNE, IDLE and ORE interrupts only. +// Notes: +// - ORE (overrun error) is tied to the RXNE IRQ line. +// - On STM32F4 the IRQ flags are cleared by reading SR then DR. void uart_irq_handler(mp_uint_t uart_id) { // get the uart object pyb_uart_obj_t *self = MP_STATE_PORT(pyb_uart_obj_all)[uart_id - 1]; @@ -966,16 +1008,28 @@ void uart_irq_handler(mp_uint_t uart_id) { return; } - if (UART_RXNE_IS_SET(self->uartx)) { + // Capture IRQ status flags. + #if defined(STM32F4) + self->mp_irq_flags = self->uartx->SR; + bool rxne_is_set = self->mp_irq_flags & USART_SR_RXNE; + bool did_clear_sr = false; + #else + self->mp_irq_flags = self->uartx->ISR; + bool rxne_is_set = self->mp_irq_flags & USART_ISR_RXNE; + #endif + + // Process RXNE flag, either read the character or disable the interrupt. + if (rxne_is_set) { if (self->read_buf_len != 0) { 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) || defined(STM32WB) int data = self->uartx->RDR; // clears UART_FLAG_RXNE - self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set #else + self->mp_irq_flags = self->uartx->SR; // resample to get any new flags since next read of DR will clear SR int data = self->uartx->DR; // clears UART_FLAG_RXNE + did_clear_sr = true; #endif data &= self->char_mask; if (self->attached_to_repl && data == mp_interrupt_char) { @@ -992,32 +1046,32 @@ void uart_irq_handler(mp_uint_t uart_id) { } else { // No room: leave char in buf, disable interrupt UART_RXNE_IT_DIS(self->uartx); } + } else { + // No buffering, disable interrupt. + UART_RXNE_IT_DIS(self->uartx); } } - // 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; + // Clear other interrupt flags that can trigger this IRQ handler. #if defined(STM32F4) - if (self->uartx->SR & USART_SR_IDLE) { - (void)self->uartx->SR; - (void)self->uartx->DR; - self->mp_irq_flags |= UART_FLAG_IDLE; + if (did_clear_sr) { + // SR was cleared above. Re-enable IDLE if it should be enabled. + if (self->mp_irq_trigger & UART_FLAG_IDLE) { + self->uartx->CR1 |= USART_CR1_IDLEIE; + } + } else { + // On STM32F4 the only way to clear flags is to read SR then DR, but that may + // lead to a loss of data in DR. So instead the IRQs are disabled. + if (self->mp_irq_flags & USART_SR_IDLE) { + self->uartx->CR1 &= ~USART_CR1_IDLEIE; + } + if (self->mp_irq_flags & USART_SR_ORE) { + // ORE is tied to RXNE so that must be disabled. + self->uartx->CR1 &= ~USART_CR1_RXNEIE; + } } #else - if (self->uartx->ISR & USART_ISR_IDLE) { - self->uartx->ICR = USART_ICR_IDLECF; - self->mp_irq_flags |= UART_FLAG_IDLE; - } + self->uartx->ICR = self->mp_irq_flags & (USART_ICR_IDLECF | USART_ICR_ORECF); #endif // Check the flags to see if the user handler should be called diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 1ed45592e..9a9600f89 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -396,6 +396,35 @@ usbd_cdc_itf_t *usb_vcp_get(int idx) { pyb.usb_mode(..., port=2) # for second USB port */ +typedef struct _pyb_usb_mode_table_t { + uint8_t usbd_mode; + uint16_t qst; + const char *deprecated_str; + uint16_t default_pid; +} pyb_usb_mode_table_t; + +// These are all the modes supported by USBD_SelectMode. +// Note: there are some names (eg CDC, VCP+VCP) which are supported for backwards compatibility. +STATIC const pyb_usb_mode_table_t pyb_usb_mode_table[] = { + { USBD_MODE_CDC, MP_QSTR_VCP, "CDC", MICROPY_HW_USB_PID_CDC }, + { USBD_MODE_MSC, MP_QSTR_MSC, NULL, MICROPY_HW_USB_PID_MSC }, + { USBD_MODE_CDC_MSC, MP_QSTR_VCP_plus_MSC, "CDC+MSC", MICROPY_HW_USB_PID_CDC_MSC }, + { USBD_MODE_CDC_HID, MP_QSTR_VCP_plus_HID, "CDC+HID", MICROPY_HW_USB_PID_CDC_HID }, + { USBD_MODE_CDC_MSC_HID, MP_QSTR_VCP_plus_MSC_plus_HID, NULL, MICROPY_HW_USB_PID_CDC_MSC_HID }, + + #if MICROPY_HW_USB_CDC_NUM >= 2 + { USBD_MODE_CDC2, MP_QSTR_2xVCP, "VCP+VCP", MICROPY_HW_USB_PID_CDC2 }, + { USBD_MODE_CDC2_MSC, MP_QSTR_2xVCP_plus_MSC, "VCP+VCP+MSC", MICROPY_HW_USB_PID_CDC2_MSC }, + { USBD_MODE_CDC2_MSC_HID, MP_QSTR_2xVCP_plus_MSC_plus_HID, NULL, MICROPY_HW_USB_PID_CDC2_MSC_HID }, + #endif + + #if MICROPY_HW_USB_CDC_NUM >= 3 + { USBD_MODE_CDC3, MP_QSTR_3xVCP, NULL, MICROPY_HW_USB_PID_CDC3 }, + { USBD_MODE_CDC3_MSC, MP_QSTR_3xVCP_plus_MSC, NULL, MICROPY_HW_USB_PID_CDC3_MSC }, + { USBD_MODE_CDC3_MSC_HID, MP_QSTR_3xVCP_plus_MSC_plus_HID, NULL, MICROPY_HW_USB_PID_CDC3_MSC_HID }, + #endif +}; + 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, @@ -430,23 +459,14 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * #if defined(USE_HOST_MODE) return MP_OBJ_NEW_QSTR(MP_QSTR_host); #else - uint8_t mode = USBD_GetMode(&usb_device.usbd_cdc_msc_hid_state); - switch (mode & USBD_MODE_IFACE_MASK) { - case USBD_MODE_CDC: - return MP_OBJ_NEW_QSTR(MP_QSTR_VCP); - case USBD_MODE_MSC: - return MP_OBJ_NEW_QSTR(MP_QSTR_MSC); - case USBD_MODE_HID: - return MP_OBJ_NEW_QSTR(MP_QSTR_HID); - case USBD_MODE_CDC_MSC: - return MP_OBJ_NEW_QSTR(MP_QSTR_VCP_plus_MSC); - case USBD_MODE_CDC_HID: - return MP_OBJ_NEW_QSTR(MP_QSTR_VCP_plus_HID); - case USBD_MODE_MSC_HID: - return MP_OBJ_NEW_QSTR(MP_QSTR_MSC_plus_HID); - default: - return mp_const_none; + uint8_t mode = USBD_GetMode(&usb_device.usbd_cdc_msc_hid_state) & USBD_MODE_IFACE_MASK; + for (size_t i = 0; i < MP_ARRAY_SIZE(pyb_usb_mode_table); ++i) { + const pyb_usb_mode_table_t *m = &pyb_usb_mode_table[i]; + if (mode == m->usbd_mode) { + return MP_OBJ_NEW_QSTR(m->qst); + } } + return mp_const_none; #endif } @@ -483,70 +503,21 @@ 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[ARG_vid].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) { - pid = MICROPY_HW_USB_PID_CDC_MSC; + uint8_t mode = 0; + for (size_t i = 0; i < MP_ARRAY_SIZE(pyb_usb_mode_table); ++i) { + const pyb_usb_mode_table_t *m = &pyb_usb_mode_table[i]; + if (strcmp(mode_str, qstr_str(m->qst)) == 0 + || (m->deprecated_str != NULL && strcmp(mode_str, m->deprecated_str) == 0)) { + if (pid == -1) { + pid = m->default_pid; + } + mode = m->usbd_mode; + break; } - mode = USBD_MODE_CDC_MSC; - } else if (strcmp(mode_str, "VCP+MSC+HID") == 0) { - if (pid == -1) { - pid = MICROPY_HW_USB_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) { - pid = MICROPY_HW_USB_PID_CDC2; - } - mode = USBD_MODE_CDC2; - } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) { - if (pid == -1) { - pid = MICROPY_HW_USB_PID_CDC2_MSC; - } - mode = USBD_MODE_CDC2_MSC; - } else if (strcmp(mode_str, "2xVCP+MSC+HID") == 0) { - if (pid == -1) { - pid = MICROPY_HW_USB_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) { - if (pid == -1) { - pid = MICROPY_HW_USB_PID_CDC3; - } - mode = USBD_MODE_CDC3; - } else if (strcmp(mode_str, "3xVCP+MSC") == 0) { - if (pid == -1) { - pid = MICROPY_HW_USB_PID_CDC3_MSC; - } - mode = USBD_MODE_CDC3_MSC; - } else if (strcmp(mode_str, "3xVCP+MSC+HID") == 0) { - if (pid == -1) { - pid = MICROPY_HW_USB_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) { - pid = MICROPY_HW_USB_PID_CDC_HID; - } - mode = USBD_MODE_CDC_HID; - } else if (strcmp(mode_str, "CDC") == 0 || strcmp(mode_str, "VCP") == 0) { - if (pid == -1) { - pid = MICROPY_HW_USB_PID_CDC; - } - mode = USBD_MODE_CDC; - } else if (strcmp(mode_str, "MSC") == 0) { - if (pid == -1) { - pid = MICROPY_HW_USB_PID_MSC; - } - mode = USBD_MODE_MSC; - } else { + } + if (mode == 0) { goto bad_mode; } diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 61a7c8248..b369524ca 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -37,6 +37,7 @@ #include #include +#include "boardctrl.h" #include "usbd_cdc_msc_hid.h" #include "usbd_cdc_interface.h" #include "pendsv.h" @@ -308,7 +309,7 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) { } } - usbd_cdc_rx_event_callback(cdc); + MICROPY_BOARD_USBD_CDC_RX_EVENT(cdc); if ((cdc->flow & USBD_CDC_FLOWCONTROL_RTS) && (usbd_cdc_rx_buffer_full(cdc))) { cdc->rx_buf_full = true; diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index d24881d20..50e10ba17 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -59,6 +59,7 @@ PCD_HandleTypeDef pcd_hs_handle; * @retval None */ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { + #if MICROPY_HW_USB_FS if (hpcd->Instance == USB_OTG_FS) { #if defined(STM32H7) const uint32_t otg_alt = GPIO_AF10_OTG1_FS; @@ -125,12 +126,18 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { NVIC_SetPriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS); HAL_NVIC_EnableIRQ(OTG_FS_IRQn); #endif + + return; } + #endif + #if MICROPY_HW_USB_HS - else if (hpcd->Instance == USB_OTG_HS) { + if (hpcd->Instance == USB_OTG_HS) { #if MICROPY_HW_USB_HS_IN_FS - #if defined(STM32H7) + #if defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) + const uint32_t otg_alt = GPIO_AF10_OTG1_FS; + #elif defined(STM32H7) const uint32_t otg_alt = GPIO_AF12_OTG2_FS; #else const uint32_t otg_alt = GPIO_AF12_OTG_HS_FS; @@ -204,13 +211,17 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) { __HAL_RCC_USB_CLK_DISABLE(); #else + #if MICROPY_HW_USB_FS if (hpcd->Instance == USB_OTG_FS) { /* Disable USB FS Clocks */ __USB_OTG_FS_CLK_DISABLE(); __SYSCFG_CLK_DISABLE(); + return; } + #endif + #if MICROPY_HW_USB_HS - else if (hpcd->Instance == USB_OTG_HS) { + if (hpcd->Instance == USB_OTG_HS) { /* Disable USB FS Clocks */ __USB_OTG_HS_CLK_DISABLE(); __SYSCFG_CLK_DISABLE(); diff --git a/ports/teensy/Makefile b/ports/teensy/Makefile index d1ff42162..fe46b0e06 100644 --- a/ports/teensy/Makefile +++ b/ports/teensy/Makefile @@ -6,6 +6,42 @@ QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h # MicroPython feature configurations MICROPY_ROM_TEXT_COMPRESSION ?= 1 +USE_FROZEN = 1 +USE_MEMZIP = 0 + +ifeq ($(USE_MEMZIP),1) +SRC_C += \ + shared/memzip/import.c \ + shared/memzip/lexermemzip.c \ + shared/memzip/memzip.c \ + +OBJ += $(BUILD)/memzip-files.o + +MAKE_MEMZIP = $(TOP)/shared/memzip/make-memzip.py +ifeq ($(MEMZIP_DIR),) +MEMZIP_DIR = memzip_files +endif + +$(BUILD)/memzip-files.o: $(BUILD)/memzip-files.c + $(call compile_c) + +$(BUILD)/memzip-files.c: $(shell find ${MEMZIP_DIR} -type f) + @$(ECHO) "Creating $@" + $(Q)$(PYTHON) $(MAKE_MEMZIP) --zip-file $(BUILD)/memzip-files.zip --c-file $@ $(MEMZIP_DIR) + +endif # USE_MEMZIP + +ifeq ($(USE_FROZEN),1) + +FROZEN_MANIFEST ?= "manifest.py" + +CFLAGS += -DMICROPY_MODULE_FROZEN_STR + +SRC_C += \ + lexerfrozen.c + +endif # USE_FROZEN + # include py core make definitions include $(TOP)/py/py.mk @@ -76,10 +112,7 @@ endif CFLAGS += -fdata-sections -ffunction-sections LDFLAGS += -Wl,--gc-sections -USE_FROZEN = 1 -USE_MEMZIP = 0 - -SRC_C = \ +SRC_C += \ hal_ftm.c \ hal_gpio.c \ help.c \ @@ -127,42 +160,6 @@ OBJ += $(BUILD)/pins_gen.o all: hex hex: $(BUILD)/micropython.hex -ifeq ($(USE_MEMZIP),1) -SRC_C += \ - shared/memzip/import.c \ - shared/memzip/lexermemzip.c \ - shared/memzip/memzip.c \ - -OBJ += $(BUILD)/memzip-files.o - -MAKE_MEMZIP = $(TOP)/shared/memzip/make-memzip.py -ifeq ($(MEMZIP_DIR),) -MEMZIP_DIR = memzip_files -endif - -$(BUILD)/memzip-files.o: $(BUILD)/memzip-files.c - $(call compile_c) - -$(BUILD)/memzip-files.c: $(shell find ${MEMZIP_DIR} -type f) - @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MAKE_MEMZIP) --zip-file $(BUILD)/memzip-files.zip --c-file $@ $(MEMZIP_DIR) - -endif # USE_MEMZIP - -ifeq ($(USE_FROZEN),1) - -ifeq ($(FROZEN_DIR),) -FROZEN_DIR = memzip_files -endif - -CFLAGS += -DMICROPY_MODULE_FROZEN_STR - -SRC_C += \ - lexerfrozen.c \ - $(BUILD)/frozen.c - -endif # USE_FROZEN - ifeq ($(ARDUINO),) post_compile: $(BUILD)/micropython.hex $(ECHO) "Please define ARDUINO (where TeensyDuino is installed)" diff --git a/ports/teensy/main.c b/ports/teensy/main.c index 6ebdcde21..37a04c74f 100644 --- a/ports/teensy/main.c +++ b/ports/teensy/main.c @@ -269,9 +269,6 @@ soft_reset: // MicroPython init mp_init(); - mp_obj_list_init(mp_sys_path, 0); - 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); readline_init0(); diff --git a/ports/teensy/manifest.py b/ports/teensy/manifest.py new file mode 100644 index 000000000..1fefd6868 --- /dev/null +++ b/ports/teensy/manifest.py @@ -0,0 +1 @@ +freeze_as_str("$(PORT_DIR)/memzip_files") diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 24c8ab562..a2dbf5af3 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -13,10 +13,8 @@ include ../../py/mkenv.mk -include mpconfigport.mk include $(VARIANT_DIR)/mpconfigvariant.mk -# use FROZEN_MANIFEST for new projects, others are legacy +# Use the default frozen manifest, variants may override this. FROZEN_MANIFEST ?= variants/manifest.py -FROZEN_DIR = -FROZEN_MPY_DIR = # This should be configured by the mpconfigvariant.mk PROG ?= micropython @@ -44,8 +42,7 @@ CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DI # Debugging/Optimization ifdef DEBUG -CFLAGS += -g3 -COPT ?= -O0 +COPT ?= -Og else COPT ?= -Os COPT += -DNDEBUG @@ -293,16 +290,12 @@ SRC_QSTR += $(SRC_C) $(SRC_CXX) $(LIB_SRC_C) $(SHARED_SRC_C) $(EXTMOD_SRC_C) # SRC_QSTR SRC_QSTR_AUTO_DEPS += -ifneq ($(FROZEN_MANIFEST)$(FROZEN_MPY_DIR),) +ifneq ($(FROZEN_MANIFEST),) # 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 -MPY_CROSS_FLAGS += -mcache-lookup-bc -endif - -ifneq ($(FROZEN_MANIFEST)$(FROZEN_DIR),) CFLAGS += -DMICROPY_MODULE_FROZEN_STR endif @@ -315,9 +308,7 @@ endif CXXFLAGS += $(filter-out -Wmissing-prototypes -Wold-style-definition -std=gnu99,$(CFLAGS) $(CXXFLAGS_MOD)) ifeq ($(MICROPY_FORCE_32BIT),1) -RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc -march=x86' -else -RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-mcache-lookup-bc' +RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-march=x86' endif ifeq ($(CROSS_COMPILE),arm-linux-gnueabi-) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index d5b5d8dd7..6b00cdfef 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -153,7 +153,7 @@ STATIC void pairheap_test(size_t nops, int *ops) { mp_pairheap_init_node(pairheap_lt, &node[i]); } mp_pairheap_t *heap = mp_pairheap_new(pairheap_lt); - printf("create:"); + mp_printf(&mp_plat_print, "create:"); for (size_t i = 0; i < nops; ++i) { if (ops[i] >= 0) { heap = mp_pairheap_push(pairheap_lt, heap, &node[ops[i]]); @@ -167,13 +167,13 @@ STATIC void pairheap_test(size_t nops, int *ops) { ; } } - printf("\npop all:"); + mp_printf(&mp_plat_print, "\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"); + mp_printf(&mp_plat_print, "\n"); } // function to run extra tests for things that can't be checked by scripts diff --git a/ports/unix/main.c b/ports/unix/main.c index 031bdd75d..b2790791a 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -495,11 +495,7 @@ MP_NOINLINE int main_(int argc, char **argv) { char *home = getenv("HOME"); char *path = getenv("MICROPYPATH"); if (path == NULL) { - #ifdef MICROPY_PY_SYS_PATH_DEFAULT path = MICROPY_PY_SYS_PATH_DEFAULT; - #else - path = "~/.micropython/lib:/usr/lib/micropython"; - #endif } size_t path_num = 1; // [0] is for current dir (or base dir of the script) if (*path == PATHLIST_SEP_CHAR) { @@ -658,7 +654,7 @@ MP_NOINLINE int main_(int argc, char **argv) { break; } - // Set base dir of the script as first entry in sys.path + // Set base dir of the script as first entry in sys.path. char *p = strrchr(basedir, '/'); path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir); free(pathbuf); diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 5e719c573..24e5c95b1 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -49,6 +50,29 @@ #define USE_STATFS 1 #endif +#if defined(__GLIBC__) && defined(__GLIBC_PREREQ) +#if __GLIBC_PREREQ(2, 25) +#include +#define _HAVE_GETRANDOM +#endif +#endif + +STATIC mp_obj_t mod_os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + #ifdef _HAVE_GETRANDOM + RAISE_ERRNO(getrandom(vstr.buf, n, 0), errno); + #else + int fd = open("/dev/urandom", O_RDONLY); + RAISE_ERRNO(fd, errno); + RAISE_ERRNO(read(fd, vstr.buf, n), errno); + close(fd); + #endif + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_urandom_obj, mod_os_urandom); + 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); @@ -309,6 +333,7 @@ STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) }, { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mod_os_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mod_os_urandom_obj) }, #if MICROPY_PY_OS_STATVFS { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mod_os_statvfs_obj) }, #endif diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index 1c9ef3362..951cb7a21 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -46,6 +46,7 @@ #include "py/builtin.h" #include "py/mphal.h" #include "py/mpthread.h" +#include /* The idea of this module is to implement reasonable minimum of @@ -144,6 +145,29 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i case MP_STREAM_GET_FILENO: return self->fd; + #if MICROPY_PY_USELECT + case MP_STREAM_POLL: { + mp_uint_t ret = 0; + uint8_t pollevents = 0; + if (arg & MP_STREAM_POLL_RD) { + pollevents |= POLLIN; + } + if (arg & MP_STREAM_POLL_WR) { + pollevents |= POLLOUT; + } + struct pollfd pfd = { .fd = self->fd, .events = pollevents }; + if (poll(&pfd, 1, 0) > 0) { + if (pfd.revents & POLLIN) { + ret |= MP_STREAM_POLL_RD; + } + if (pfd.revents & POLLOUT) { + ret |= MP_STREAM_POLL_WR; + } + } + return ret; + } + #endif + default: *errcode = MP_EINVAL; return MP_STREAM_ERROR; diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index b8bfbd2b8..098a9f47a 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -81,10 +81,14 @@ #endif #define MICROPY_STREAMS_POSIX_API (1) #define MICROPY_OPT_COMPUTED_GOTO (1) -#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) +#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH +#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1) +#endif +#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE +#define MICROPY_OPT_MAP_LOOKUP_CACHE (1) #endif #define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_VFS_POSIX_FILE (1) #define MICROPY_PY_FUNCTION_ATTRS (1) @@ -108,6 +112,7 @@ #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_PATH_ARGV_DEFAULTS (0) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_ATEXIT (1) #if MICROPY_PY_SYS_SETTRACE @@ -123,6 +128,9 @@ #define LINUX_FRAME_BUFFER 1 #endif #endif +#ifndef MICROPY_PY_SYS_PATH_DEFAULT +#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:/usr/lib/micropython" +#endif #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_SYS_EXC_INFO (1) diff --git a/ports/unix/variants/coverage/mpconfigvariant.h b/ports/unix/variants/coverage/mpconfigvariant.h index 942117608..f033dddb1 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.h +++ b/ports/unix/variants/coverage/mpconfigvariant.h @@ -51,7 +51,6 @@ #define MICROPY_PY_MATH_FACTORIAL (1) #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) #define MICROPY_PY_IO_BUFFEREDWRITER (1) -#define MICROPY_PY_IO_RESOURCE_STREAM (1) #define MICROPY_PY_UASYNCIO (1) #define MICROPY_PY_URE_DEBUG (1) #define MICROPY_PY_URE_MATCH_GROUPS (1) diff --git a/ports/unix/variants/minimal/mpconfigvariant.h b/ports/unix/variants/minimal/mpconfigvariant.h index e87b5d8ec..e0db3756c 100644 --- a/ports/unix/variants/minimal/mpconfigvariant.h +++ b/ports/unix/variants/minimal/mpconfigvariant.h @@ -55,7 +55,8 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) #define MICROPY_STREAMS_NON_BLOCK (0) #define MICROPY_OPT_COMPUTED_GOTO (0) -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) +#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (0) +#define MICROPY_OPT_MAP_LOOKUP_CACHE (0) #define MICROPY_CAN_OVERRIDE_BUILTINS (0) #define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0) #define MICROPY_CPYTHON_COMPAT (0) @@ -87,6 +88,9 @@ #define MICROPY_PY_SYS (1) #define MICROPY_PY_SYS_EXIT (0) #define MICROPY_PY_SYS_PLATFORM "linux" +#ifndef MICROPY_PY_SYS_PATH_DEFAULT +#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen:~/.micropython/lib:/usr/lib/micropython" +#endif #define MICROPY_PY_SYS_MAXSIZE (0) #define MICROPY_PY_SYS_STDFILES (0) #define MICROPY_PY_CMATH (0) diff --git a/ports/windows/.appveyor.yml b/ports/windows/.appveyor.yml index 40fdff293..739484f09 100644 --- a/ports/windows/.appveyor.yml +++ b/ports/windows/.appveyor.yml @@ -5,6 +5,10 @@ skip_tags: true environment: # Python version used MICROPY_CPYTHON3: c:/python38/python.exe + # The variants. + matrix: + - PyVariant: dev + - PyVariant: standard init: # Set build version number to commit to be travis-like @@ -18,6 +22,12 @@ platform: - x86 - x64 +matrix: + # One debug build is enough. + exclude: + - configuration: Debug + PyVariant: dev + before_build: - ps: | @" @@ -36,6 +46,7 @@ build: test_script: - ps: | + $env:MICROPY_MICROPYTHON=(msbuild ports\windows\micropython.vcxproj /nologo /v:m /t:ShowTargetPath).Trim() cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'tests') & $env:MICROPY_CPYTHON3 run-tests.py if ($LASTEXITCODE -ne 0) { @@ -57,27 +68,17 @@ after_test: } $env:MSYSTEM = if ($platform -eq 'x86') {'MINGW32'} else {'MINGW64'} $env:CHERE_INVOKING = 'enabled_from_arguments' - cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows') - C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1" - if ($LASTEXITCODE -ne 0) { - throw "$env:MSYSTEM build exited with code $LASTEXITCODE" - } cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'mpy-cross') C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1" if ($LASTEXITCODE -ne 0) { throw "$env:MSYSTEM mpy_cross build exited with code $LASTEXITCODE" } - cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'tests') - $testArgs = @('run-tests.py') - foreach ($skipTest in @('math_fun', 'float2int_double', 'float_parse', 'math_domain_special')) { - $testArgs = $testArgs + '-e' + $skipTest + cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows') + C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1 MICROPY_MPYCROSS=../../mpy-cross/mpy-cross.exe VARIANT=$($env:PyVariant)" + if ($LASTEXITCODE -ne 0) { + throw "$env:MSYSTEM build exited with code $LASTEXITCODE" } - & $env:MICROPY_CPYTHON3 $testArgs - if ($LASTEXITCODE -ne 0) { - & $env:MICROPY_CPYTHON3 run-tests.py --print-failures - throw "Test failure" - } - & $env:MICROPY_CPYTHON3 ($testArgs + @('--via-mpy', '-d', 'basics', 'float', 'micropython')) + C:\msys64\usr\bin\bash.exe -l -c "make V=1 test_full VARIANT=$($env:PyVariant)" if ($LASTEXITCODE -ne 0) { & $env:MICROPY_CPYTHON3 run-tests.py --print-failures throw "Test failure" diff --git a/ports/windows/Makefile b/ports/windows/Makefile index c5b5e879e..6c86d7440 100644 --- a/ports/windows/Makefile +++ b/ports/windows/Makefile @@ -1,11 +1,27 @@ +# 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 -# define main target -PROG = micropython +FROZEN_MANIFEST ?= variants/manifest.py + +# Define main target +# This should be configured by the mpconfigvariant.mk +PROG ?= micropython # qstr definitions (must come before including py.mk) QSTR_DEFS = ../unix/qstrdefsport.h +QSTR_GLOBAL_DEPENDENCIES = $(VARIANT_DIR)/mpconfigvariant.h # include py core make definitions include $(TOP)/py/py.mk @@ -13,6 +29,7 @@ include $(TOP)/py/py.mk INC += -I. INC += -I$(TOP) INC += -I$(BUILD) +INC += -I$(VARIANT_DIR) # compiler settings CFLAGS = $(INC) -Wall -Wpointer-arith -Wdouble-promotion -Werror -std=gnu99 -DUNIX -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) @@ -41,7 +58,8 @@ SRC_C = \ init.c \ sleep.c \ fmode.c \ - $(SRC_MOD) + $(SRC_MOD) \ + $(wildcard $(VARIANT_DIR)/*.c) LIB_SRC_C = $(addprefix lib/,\ lv_bindings/driver/SDL/SDL_monitor.c \ @@ -68,7 +86,18 @@ SRC_QSTR_AUTO_DEPS += ifneq ($(FROZEN_MANIFEST),) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool -DMICROPY_MODULE_FROZEN_MPY=1 -DMPZ_DIG_SIZE=16 -MPY_CROSS_FLAGS += -mcache-lookup-bc endif include $(TOP)/py/mkrules.mk + +.PHONY: test test_full + +RUN_TESTS_SKIP += -e math_fun -e float2int_double -e float_parse -e math_domain_special + +test: $(PROG) $(TOP)/tests/run-tests.py + $(eval DIRNAME=ports/$(notdir $(CURDIR))) + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) $(PYTHON) ./run-tests.py $(RUN_TESTS_SKIP) + +test_full: test + $(eval DIRNAME=ports/$(notdir $(CURDIR))) + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) $(PYTHON) ./run-tests.py --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) $(RUN_TESTS_SKIP) -d basics float micropython diff --git a/ports/windows/README.md b/ports/windows/README.md index 553e87513..713ea82b8 100644 --- a/ports/windows/README.md +++ b/ports/windows/README.md @@ -25,8 +25,7 @@ Install Cygwin, then install following packages using Cygwin's setup.exe: * mingw64-i686-gcc-core * mingw64-x86_64-gcc-core * make - -Also install the python3 package, or install Python globally for Windows (see below). +* python3 Build using: @@ -72,6 +71,26 @@ To build from the command line: msbuild ../../mpy-cross/mpy-cross.vcxproj msbuild micropython.vcxproj +__Variants__ + +The msvc port supports variants (like the unix and windows mingw ports) and the one which gets built is +controlled by the `PyVariant` msbuild property. It defaults to `standard`. +The other variants can be built like: + + msbuild micropython.vcxproj /p:PyVariant=dev + +Or by adding a file [Directory.build.props](https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build#directorybuildprops-and-directorybuildtargets) in this directory or a parent directory: + +```xml + + + dev + + +``` + +See [paths.props](msvc/paths.props) for other related variables like build and variant directories. + __Stack usage__ The msvc compiler is quite stack-hungry which might result in a "maximum recursion depth exceeded" diff --git a/ports/windows/micropython.vcxproj b/ports/windows/micropython.vcxproj index 1beca9e50..6817d6ed1 100644 --- a/ports/windows/micropython.vcxproj +++ b/ports/windows/micropython.vcxproj @@ -64,6 +64,7 @@ msvc/user.props + $(PyProg) @@ -95,6 +96,7 @@ + diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index a8340e9a2..7be14ca97 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -26,6 +26,9 @@ // options to control how MicroPython is built +// Variant-specific definitions. +#include "mpconfigvariant.h" + // By default use MicroPython version of readline #ifndef MICROPY_USE_READLINE #define MICROPY_USE_READLINE (1) @@ -55,13 +58,17 @@ #define MICROPY_REPL_AUTO_INDENT (1) #define MICROPY_HELPER_LEXER_UNIX (1) #define MICROPY_ENABLE_SOURCE_LINE (1) +#ifndef MICROPY_FLOAT_IMPL #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) +#endif #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 (0) -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) #define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_VFS_POSIX_FILE (1) #define MICROPY_PY_FUNCTION_ATTRS (1) @@ -78,33 +85,42 @@ #define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) #define MICROPY_PY_BUILTINS_INPUT (1) #define MICROPY_PY_BUILTINS_POW3 (1) +#ifndef MICROPY_PY_BUILTINS_HELP +#define MICROPY_PY_BUILTINS_HELP (1) +#endif +#ifndef MICROPY_PY_BUILTINS_HELP_MODULES +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#endif #define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (0) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_ATEXIT (1) #define MICROPY_PY_SYS_PLATFORM "win32" #ifndef MICROPY_PY_SYS_PATH_DEFAULT -#define MICROPY_PY_SYS_PATH_DEFAULT "~/.micropython/lib" +#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen;~/.micropython/lib" #endif #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_SYS_EXC_INFO (1) #define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) -#define MICROPY_PY_MATH_ISCLOSE (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) #define MICROPY_PY_GC_COLLECT_RETVAL (1) -#define MICROPY_MODULE_FROZEN_STR (0) - +#ifndef MICROPY_STACKLESS #define MICROPY_STACKLESS (0) #define MICROPY_STACKLESS_STRICT (0) +#endif #define MICROPY_PY_UTIME (1) #define MICROPY_PY_UTIME_MP_HAL (1) diff --git a/ports/windows/mpconfigport.mk b/ports/windows/mpconfigport.mk index a2c618f14..3b7cf2100 100644 --- a/ports/windows/mpconfigport.mk +++ b/ports/windows/mpconfigport.mk @@ -1,12 +1,9 @@ # Enable/disable modules and 3rd-party libs to be included in interpreter # Build 32-bit binaries on a 64-bit host -MICROPY_FORCE_32BIT = 0 +MICROPY_FORCE_32BIT ?= 0 # This variable can take the following values: # 0 - no readline, just simple stdin input # 1 - use MicroPython version of readline -MICROPY_USE_READLINE = 1 - -# ffi module requires libffi (libffi-dev Debian package) -MICROPY_PY_FFI = 0 +MICROPY_USE_READLINE ?= 1 diff --git a/ports/windows/msvc/common.props b/ports/windows/msvc/common.props index fcad5aeb6..7d608a379 100644 --- a/ports/windows/msvc/common.props +++ b/ports/windows/msvc/common.props @@ -1,7 +1,15 @@  + + + standard + build-$(PyVariant) + + @@ -31,8 +39,14 @@ $(PyTargetDir)%(FileName)%(Extension) + + + + + + + $(PlatformToolset.Replace('v', '')) + True + + @@ -57,6 +63,7 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) { + False $([System.String]::new('%(FullPath)').Replace('$(PyBaseDir)', '$(DestDir)qstr\')) @@ -71,13 +78,21 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) { + $(PyClTool) /nologo /I@(PyIncDirs, ' /I') /D@(PreProcDefs, ' /D') @(QstrDependencies->AnyHaveMetadataValue('Changed', 'True')) @(PyQstrSourceFiles->AnyHaveMetadataValue('Changed', 'True')) + + + $(PyPreProcCommand) /Fi%(OutFile) /P %(Identity) + %(OutFile) + + + + + + - - @@ -123,7 +138,7 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) { MICROPY_MODULE_FROZEN_MPY=1;MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool;%(PreprocessorDefinitions) - + diff --git a/ports/windows/msvc/paths.props b/ports/windows/msvc/paths.props index cfd43b708..1a4191932 100644 --- a/ports/windows/msvc/paths.props +++ b/ports/windows/msvc/paths.props @@ -11,13 +11,15 @@ |- ports/windows [PyWinDir] |- ... |- micropython.exe - |- build [PyBuildDir] + |- build-standard [PyBuildDir] |- Debugx64 [PyOutDir] | |- ... | |- micropython.exe | |- micropython.map | |- obj [PyIntDir] |- genhdr + |- variants + |- standard [PyVariantDir] Note that the micropython executable will be copied from PyOutDir to PyWinDir after each build. --> @@ -25,11 +27,12 @@ $([System.IO.Path]::GetFullPath(`$(MSBuildThisFileDirectory)..\..\..`))\ $(PyBaseDir)ports\windows\ - $(PyWinDir)build\ + $(PyWinDir)$(PyBuild)\ + $(PyWinDir)variants\$(PyVariant)\ $(PyWinDir) - $(PyIncDirs);$(PyBaseDir);$(PyWinDir);$(PyBuildDir);$(PyWinDir)msvc + $(PyIncDirs);$(PyBaseDir);$(PyWinDir);$(PyBuildDir);$(PyWinDir)msvc;$(PyVariantDir) "a.foo.bar" + // "Relative imports use a module's __name__ attribute to determine that + // module's position in the package hierarchy." + // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name + + mp_obj_t current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); + assert(current_module_name_obj != MP_OBJ_NULL); + + #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT && MICROPY_CPYTHON_COMPAT + if (MP_OBJ_QSTR_VALUE(current_module_name_obj) == MP_QSTR___main__) { + // This is a module loaded by -m command-line switch (e.g. unix port), + // and so its __name__ has been set to "__main__". Get its real name + // that we stored during import in the __main__ attribute. + current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + } + #endif + + // If we have a __path__ in the globals dict, then we're a package. + bool is_pkg = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); + + #if DEBUG_PRINT + DEBUG_printf("Current module/package: "); + mp_obj_print_helper(MICROPY_DEBUG_PRINTER, current_module_name_obj, PRINT_REPR); + DEBUG_printf(", is_package: %d", is_pkg); + DEBUG_printf("\n"); + #endif + + size_t current_module_name_len; + const char *current_module_name = mp_obj_str_get_data(current_module_name_obj, ¤t_module_name_len); + + const char *p = current_module_name + current_module_name_len; + if (is_pkg) { + // If we're evaluating relative to a package, then take off one fewer + // level (i.e. the relative search starts inside the package, rather + // than as a sibling of the package). + --level; + } + + // Walk back 'level' dots (or run out of path). + while (level && p > current_module_name) { if (*--p == '.') { - *end = p; - return; + --level; } } - *end = p; + + // We must have some component left over to import from. + if (p == current_module_name) { + mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("can't perform relative import")); + } + + // New length is len("."). Note: might be one byte + // more than we need if module_name is empty (for the extra . we will + // append). + uint new_module_name_len = (size_t)(p - current_module_name) + 1 + *module_name_len; + char *new_mod = mp_local_alloc(new_module_name_len); + memcpy(new_mod, current_module_name, p - current_module_name); + + // Only append "." if there was one). + if (*module_name_len != 0) { + new_mod[p - current_module_name] = '.'; + memcpy(new_mod + (p - current_module_name) + 1, *module_name, *module_name_len); + } else { + --new_module_name_len; + } + + // Copy into a QSTR. + qstr new_mod_q = qstr_from_strn(new_mod, new_module_name_len); + mp_local_free(new_mod); + + DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); + *module_name = qstr_str(new_mod_q); + *module_name_len = new_module_name_len; +} + +// Load a module at the specified absolute path, possibly as a submodule of the given outer module. +// full_mod_name: The full absolute path to this module (e.g. "foo.bar.baz"). +// level_mod_name: The final component of the path (e.g. "baz"). +// outer_module_obj: The parent module (we need to store this module as an +// attribute on it) (or MP_OBJ_NULL for top-level). +// path: The filesystem path where we found the parent module +// (or empty for a top level module). +// override_main: Whether to set the __name__ to "__main__" (and use __main__ +// for the actual path). +STATIC mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, mp_obj_t outer_module_obj, vstr_t *path, bool override_main) { + mp_import_stat_t stat = MP_IMPORT_STAT_NO_EXIST; + + // Exact-match of built-in (or already-loaded) takes priority. + mp_obj_t module_obj = mp_module_get_loaded_or_builtin(full_mod_name); + + // Even if we find the module, go through the motions of searching for it + // because we may actually be in the process of importing a sub-module. + // So we need to (re-)find the correct path to be finding the sub-module + // on the next iteration of process_import_at_level. + + if (outer_module_obj == MP_OBJ_NULL) { + DEBUG_printf("Searching for top-level module\n"); + + // First module in the dotted-name; search for a directory or file + // relative to all the locations in sys.path. + stat = stat_top_level_dir_or_file(full_mod_name, path); + + // If the module "foo" doesn't exist on the filesystem, and it's not a + // builtin, try and find "ufoo" as a built-in. (This feature was + // formerly known as "weak links"). + #if MICROPY_MODULE_WEAK_LINKS + if (stat == MP_IMPORT_STAT_NO_EXIST && module_obj == MP_OBJ_NULL) { + char *umodule_buf = vstr_str(path); + umodule_buf[0] = 'u'; + strcpy(umodule_buf + 1, qstr_str(level_mod_name)); + qstr umodule_name = qstr_from_str(umodule_buf); + module_obj = mp_module_get_builtin(umodule_name); + } + #endif + } else { + DEBUG_printf("Searching for sub-module\n"); + + // Add the current part of the module name to the path. + vstr_add_char(path, PATH_SEP_CHAR[0]); + vstr_add_str(path, qstr_str(level_mod_name)); + + // Because it's not top level, we already know which path the parent was found in. + stat = stat_dir_or_file(path); + } + DEBUG_printf("Current path: %.*s\n", (int)vstr_len(path), vstr_str(path)); + + if (module_obj == MP_OBJ_NULL) { + // Not a built-in and not already-loaded. + + if (stat == MP_IMPORT_STAT_NO_EXIST) { + // And the file wasn't found -- fail. + #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE + mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found")); + #else + mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), full_mod_name); + #endif + } + + // Not a built-in but found on the filesystem, try and load it. + + DEBUG_printf("Found path: %.*s\n", (int)vstr_len(path), vstr_str(path)); + + // Prepare for loading from the filesystem. Create a new shell module. + module_obj = mp_obj_new_module(full_mod_name); + + #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT + // If this module is being loaded via -m on unix, then + // override __name__ to "__main__". Do this only for *modules* + // however - packages never have their names replaced, instead + // they're -m'ed using a special __main__ submodule in them. (This all + // apparently is done to not touch the package name itself, which is + // important for future imports). + if (override_main && stat != MP_IMPORT_STAT_DIR) { + mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj); + mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + #if MICROPY_CPYTHON_COMPAT + // Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules). + mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj); + // Store real name in "__main__" attribute. Need this for + // resolving relative imports later. "__main__ was chosen + // semi-randonly, to reuse existing qstr's. + mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(full_mod_name)); + #endif + } + #endif // MICROPY_MODULE_OVERRIDE_MAIN_IMPORT + + if (stat == MP_IMPORT_STAT_DIR) { + // Directory -- execute "path/__init__.py". + DEBUG_printf("%.*s is dir\n", (int)vstr_len(path), vstr_str(path)); + // Store the __path__ attribute onto this module. + // https://docs.python.org/3/reference/import.html + // "Specifically, any module that contains a __path__ attribute is considered a package." + mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(path), vstr_len(path))); + size_t orig_path_len = path->len; + vstr_add_str(path, PATH_SEP_CHAR "__init__.py"); + if (stat_file_py_or_mpy(path) == MP_IMPORT_STAT_FILE) { + do_load(module_obj, path); + } else { + // No-op. Nothing to load. + // mp_warning("%s is imported as namespace package", vstr_str(&path)); + } + // Remove /__init__.py suffix. + path->len = orig_path_len; + } else { // MP_IMPORT_STAT_FILE + // File -- execute "path.(m)py". + do_load(module_obj, path); + // Note: This should be the last component in the import path. If + // there are remaining components then it's an ImportError + // because the current path(the module that was just loaded) is + // not a package. This will be caught on the next iteration + // because the file will not exist. + } + } + + if (outer_module_obj != MP_OBJ_NULL) { + // If it's a sub-module (not a built-in one), then make it available on + // the parent module. + mp_store_attr(outer_module_obj, level_mod_name, module_obj); + } + + return module_obj; } mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { @@ -248,14 +466,28 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("__import__:\n"); for (size_t i = 0; i < n_args; i++) { DEBUG_printf(" "); - mp_obj_print(args[i], PRINT_REPR); + mp_obj_print_helper(MICROPY_DEBUG_PRINTER, args[i], PRINT_REPR); DEBUG_printf("\n"); } #endif - mp_obj_t module_name = args[0]; + // This is the import path, with any leading dots stripped. + // "import foo.bar" --> module_name="foo.bar" + // "from foo.bar import baz" --> module_name="foo.bar" + // "from . import foo" --> module_name="" + // "from ...foo.bar import baz" --> module_name="foo.bar" + mp_obj_t module_name_obj = args[0]; + + // These are the imported names. + // i.e. "from foo.bar import baz, zap" --> fromtuple=("baz", "zap",) + // Note: There's a special case on the Unix port, where this is set to mp_const_false which means that it's __main__. mp_obj_t fromtuple = mp_const_none; + + // Level is the number of leading dots in a relative import. + // i.e. "from . import foo" --> level=1 + // i.e. "from ...foo.bar import baz" --> level=3 mp_int_t level = 0; + if (n_args >= 4) { fromtuple = args[3]; if (n_args >= 5) { @@ -266,211 +498,64 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } } - size_t mod_len; - const char *mod_str = mp_obj_str_get_data(module_name, &mod_len); + size_t module_name_len; + const char *module_name = mp_obj_str_get_data(module_name_obj, &module_name_len); if (level != 0) { - // What we want to do here is to take name of current module, - // chop trailing components, and concatenate with passed-in - // module name, thus resolving relative import name into absolute. - // This even appears to be correct per - // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name - // "Relative imports use a module's __name__ attribute to determine that - // module's position in the package hierarchy." - level--; - mp_obj_t this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); - assert(this_name_q != MP_OBJ_NULL); - #if MICROPY_CPYTHON_COMPAT - if (MP_OBJ_QSTR_VALUE(this_name_q) == MP_QSTR___main__) { - // This is a module run by -m command-line switch, get its real name from backup attribute - this_name_q = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); - } - #endif - mp_map_t *globals_map = &mp_globals_get()->map; - mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); - bool is_pkg = (elem != NULL); - - #if DEBUG_PRINT - DEBUG_printf("Current module/package: "); - mp_obj_print(this_name_q, PRINT_REPR); - DEBUG_printf(", is_package: %d", is_pkg); - DEBUG_printf("\n"); - #endif - - size_t this_name_l; - const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l); - - const char *p = this_name + this_name_l; - if (!is_pkg) { - // We have module, but relative imports are anchored at package, so - // go there. - chop_component(this_name, &p); - } - - while (level--) { - chop_component(this_name, &p); - } - - // We must have some component left over to import from - if (p == this_name) { - mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("can't perform relative import")); - } - - uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); - char *new_mod = mp_local_alloc(new_mod_l); - memcpy(new_mod, this_name, p - this_name); - if (mod_len != 0) { - new_mod[p - this_name] = '.'; - memcpy(new_mod + (p - this_name) + 1, mod_str, mod_len); - } - - qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l); - mp_local_free(new_mod); - DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); - module_name = MP_OBJ_NEW_QSTR(new_mod_q); - mod_str = qstr_str(new_mod_q); - mod_len = new_mod_l; + // Turn "foo.bar" into ".foo.bar". + evaluate_relative_import(level, &module_name, &module_name_len); } - if (mod_len == 0) { + if (module_name_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); - if (module_obj != MP_OBJ_NULL) { - DEBUG_printf("Module already loaded\n"); - // If it's not a package, return module right away - char *p = strchr(mod_str, '.'); - if (p == NULL) { - return module_obj; - } - // If fromlist is not empty, return leaf module - if (fromtuple != mp_const_none) { - return module_obj; - } - // Otherwise, we need to return top-level package - qstr pkg_name = qstr_from_strn(mod_str, p - mod_str); - return mp_module_get(pkg_name); - } - DEBUG_printf("Module not yet loaded\n"); + DEBUG_printf("Starting module search for '%s'\n", module_name); - uint last = 0; VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX) - module_obj = MP_OBJ_NULL; mp_obj_t top_module_obj = MP_OBJ_NULL; mp_obj_t outer_module_obj = MP_OBJ_NULL; - uint i; - for (i = 1; i <= mod_len; i++) { - if (i == mod_len || mod_str[i] == '.') { - // create a qstr for the module name up to this depth - qstr mod_name = qstr_from_strn(mod_str, i); - DEBUG_printf("Processing module: %s\n", qstr_str(mod_name)); - DEBUG_printf("Previous path: =%.*s=\n", vstr_len(&path), vstr_str(&path)); - // find the file corresponding to the module name - mp_import_stat_t stat; - if (vstr_len(&path) == 0) { - // first module in the dotted-name; search for a directory or file - stat = find_file(mod_str, i, &path); - } else { - // latter module in the dotted-name; append to path - vstr_add_char(&path, PATH_SEP_CHAR); - vstr_add_strn(&path, mod_str + last, i - last); - stat = stat_dir_or_file(&path); - } - DEBUG_printf("Current path: %.*s\n", vstr_len(&path), vstr_str(&path)); + // Search for the end of each component. + size_t current_component_start = 0; + for (size_t i = 1; i <= module_name_len; i++) { + if (i == module_name_len || module_name[i] == '.') { + // The module name up to this depth (e.g. foo.bar.baz). + qstr full_mod_name = qstr_from_strn(module_name, i); + // The current level name (e.g. baz). + qstr level_mod_name = qstr_from_strn(module_name + current_component_start, i - current_component_start); - 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) { - 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); - } - } - #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, MP_ERROR_TEXT("module not found")); - #else - mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), mod_name); - #endif - } - } else { - // found the file, so get the module - module_obj = mp_module_get(mod_name); - } + DEBUG_printf("Processing module: '%s' at level '%s'\n", qstr_str(full_mod_name), qstr_str(level_mod_name)); + DEBUG_printf("Previous path: =%.*s=\n", (int)vstr_len(&path), vstr_str(&path)); - if (module_obj == MP_OBJ_NULL) { - // module not already loaded, so load it! + #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT + // On unix, if this is being loaded via -m (magic mp_const_false), + // then handle that if it's the final component. + bool override_main = (i == module_name_len && fromtuple == mp_const_false); + #else + bool override_main = false; + #endif - module_obj = mp_obj_new_module(mod_name); + // Import this module. + mp_obj_t module_obj = process_import_at_level(full_mod_name, level_mod_name, outer_module_obj, &path, override_main); - // if args[3] (fromtuple) has magic value False, set up - // this module for command-line "-m" option (set module's - // name to __main__ instead of real name). Do this only - // for *modules* however - packages never have their names - // replaced, instead they're -m'ed using a special __main__ - // submodule in them. (This all apparently is done to not - // touch package name itself, which is important for future - // imports). - if (i == mod_len && fromtuple == mp_const_false && stat != MP_IMPORT_STAT_DIR) { - mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj); - mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); - #if MICROPY_CPYTHON_COMPAT - // Store module as "__main__" in the dictionary of loaded modules (returned by sys.modules). - mp_obj_dict_store(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_loaded_modules_dict)), MP_OBJ_NEW_QSTR(MP_QSTR___main__), module_obj); - // Store real name in "__main__" attribute. Chosen semi-randonly, to reuse existing qstr's. - mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___main__), MP_OBJ_NEW_QSTR(mod_name)); - #endif - } - - if (stat == MP_IMPORT_STAT_DIR) { - DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path)); - // https://docs.python.org/3/reference/import.html - // "Specifically, any module that contains a __path__ attribute is considered a package." - mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path))); - size_t orig_path_len = path.len; - vstr_add_char(&path, PATH_SEP_CHAR); - vstr_add_str(&path, "__init__.py"); - if (stat_file_py_or_mpy(&path) != MP_IMPORT_STAT_FILE) { - // mp_warning("%s is imported as namespace package", vstr_str(&path)); - } else { - do_load(module_obj, &path); - } - path.len = orig_path_len; - } else { // MP_IMPORT_STAT_FILE - do_load(module_obj, &path); - // This should be the last component in the import path. If there are - // remaining components then it's an ImportError because the current path - // (the module that was just loaded) is not a package. This will be caught - // on the next iteration because the file will not exist. - } - } - if (outer_module_obj != MP_OBJ_NULL) { - qstr s = qstr_from_strn(mod_str + last, i - last); - mp_store_attr(outer_module_obj, s, module_obj); - } + // Set this as the parent module, and remember the top-level module if it's the first. outer_module_obj = module_obj; if (top_module_obj == MP_OBJ_NULL) { top_module_obj = module_obj; } - last = i + 1; + + current_component_start = i + 1; } } - // If fromlist is not empty, return leaf module if (fromtuple != mp_const_none) { - return module_obj; + // If fromtuple is not empty, return leaf module + return outer_module_obj; + } else { + // Otherwise, we need to return top-level package + return top_module_obj; } - // Otherwise, we need to return top-level package - return top_module_obj; } #else // MICROPY_ENABLE_EXTERNAL_IMPORT @@ -483,17 +568,19 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // Check if module already exists, and return it if it does qstr module_name_qstr = mp_obj_str_get_qstr(args[0]); - mp_obj_t module_obj = mp_module_get(module_name_qstr); + mp_obj_t module_obj = mp_module_get_loaded_or_builtin(module_name_qstr); if (module_obj != MP_OBJ_NULL) { return module_obj; } #if MICROPY_MODULE_WEAK_LINKS // Check if there is a weak link to this module - module_obj = mp_module_search_umodule(qstr_str(module_name_qstr)); + char umodule_buf[MICROPY_ALLOC_PATH_MAX]; + umodule_buf[0] = 'u'; + strcpy(umodule_buf + 1, args[0]); + qstr umodule_name_qstr = qstr_from_str(umodule_buf); + module_obj = mp_module_get_loaded_or_builtin(umodule_name_qstr); if (module_obj != MP_OBJ_NULL) { - // Found weak-linked module - mp_module_call_init(module_name_qstr, module_obj); return module_obj; } #endif diff --git a/py/compile.c b/py/compile.c index 0b02746a5..8ebcc2289 100644 --- a/py/compile.c +++ b/py/compile.c @@ -59,6 +59,12 @@ typedef enum { #undef DEF_RULE_NC } pn_kind_t; +// Whether a mp_parse_node_struct_t that has pns->kind == PN_testlist_comp +// corresponds to a list comprehension or generator. +#define MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns) \ + (MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2 && \ + MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for)) + #define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE #if NEED_METHOD_TABLE @@ -317,25 +323,13 @@ STATIC void compile_delete_id(compiler_t *comp, qstr qst) { } } -STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) { - int total = 0; - if (!MP_PARSE_NODE_IS_NULL(pn)) { - compile_node(comp, pn); - total += 1; - } - if (pns_list != NULL) { - int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list); - for (int i = 0; i < n; i++) { - compile_node(comp, pns_list->nodes[i]); - } - total += n; - } - EMIT_ARG(build, total, MP_EMIT_BUILD_TUPLE); -} - STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) { // a simple tuple expression - c_tuple(comp, MP_PARSE_NODE_NULL, pns); + size_t num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + for (size_t i = 0; i < num_nodes; i++) { + compile_node(comp, pns->nodes[i]); + } + EMIT_ARG(build, num_nodes, MP_EMIT_BUILD_TUPLE); } STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) { @@ -452,21 +446,14 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("can't assign to expression")); } -// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail) -STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) { - uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1; - +STATIC void c_assign_tuple(compiler_t *comp, uint num_tail, mp_parse_node_t *nodes_tail) { // look for star expression uint have_star_index = -1; - if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) { - EMIT_ARG(unpack_ex, 0, num_tail); - have_star_index = 0; - } for (uint i = 0; i < num_tail; i++) { if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) { if (have_star_index == (uint)-1) { - EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1); - have_star_index = num_head + i; + EMIT_ARG(unpack_ex, i, num_tail - i - 1); + have_star_index = i; } else { compile_syntax_error(comp, nodes_tail[i], MP_ERROR_TEXT("multiple *x in assignment")); return; @@ -474,17 +461,10 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num } } if (have_star_index == (uint)-1) { - EMIT_ARG(unpack_sequence, num_head + num_tail); - } - if (num_head != 0) { - if (0 == have_star_index) { - c_assign(comp, ((mp_parse_node_struct_t *)node_head)->nodes[0], ASSIGN_STORE); - } else { - c_assign(comp, node_head, ASSIGN_STORE); - } + EMIT_ARG(unpack_sequence, num_tail); } for (uint i = 0; i < num_tail; i++) { - if (num_head + i == have_star_index) { + if (i == have_star_index) { c_assign(comp, ((mp_parse_node_struct_t *)nodes_tail[i])->nodes[0], ASSIGN_STORE); } else { c_assign(comp, nodes_tail[i], ASSIGN_STORE); @@ -526,7 +506,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ if (assign_kind != ASSIGN_STORE) { goto cannot_assign; } - c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes); + c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes); break; case PN_atom_paren: @@ -551,13 +531,13 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // empty list, assignment allowed - c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL); + c_assign_tuple(comp, 0, NULL); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { pns = (mp_parse_node_struct_t *)pns->nodes[0]; goto testlist_comp; } else { // brackets around 1 item - c_assign_tuple(comp, pns->nodes[0], 0, NULL); + c_assign_tuple(comp, 1, pns->nodes); } break; @@ -568,27 +548,10 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_ testlist_comp: // lhs is a sequence - if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { - mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1]; - if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) { - // sequence of one item, with trailing comma - assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0])); - c_assign_tuple(comp, pns->nodes[0], 0, NULL); - } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) { - // sequence of many items - uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2); - c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes); - } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) { - goto cannot_assign; - } else { - // sequence with 2 items - goto sequence_with_2_items; - } - } else { - // sequence with 2 items - sequence_with_2_items: - c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes); + if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) { + goto cannot_assign; } + c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes); return; } return; @@ -983,32 +946,11 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp)); mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn; - // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp - - if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { - mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1]; - if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3b) { - // sequence of one item, with trailing comma - assert(MP_PARSE_NODE_IS_NULL(pns1->nodes[0])); - c_del_stmt(comp, pns->nodes[0]); - } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3c) { - // sequence of many items - int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1); - c_del_stmt(comp, pns->nodes[0]); - for (int i = 0; i < n; i++) { - c_del_stmt(comp, pns1->nodes[i]); - } - } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) { - goto cannot_delete; - } else { - // sequence with 2 items - goto sequence_with_2_items; - } - } else { - // sequence with 2 items - sequence_with_2_items: - c_del_stmt(comp, pns->nodes[0]); - c_del_stmt(comp, pns->nodes[1]); + if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) { + goto cannot_delete; + } + for (size_t i = 0; i < MP_PARSE_NODE_STRUCT_NUM_NODES(pns); ++i) { + c_del_stmt(comp, pns->nodes[i]); } } } else { @@ -2490,31 +2432,16 @@ STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // an empty tuple - c_tuple(comp, MP_PARSE_NODE_NULL, NULL); + EMIT_ARG(build, 0, MP_EMIT_BUILD_TUPLE); } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)); pns = (mp_parse_node_struct_t *)pns->nodes[0]; - assert(!MP_PARSE_NODE_IS_NULL(pns->nodes[1])); - if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) { - mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[1]; - if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) { - // tuple of one item, with trailing comma - assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0])); - c_tuple(comp, pns->nodes[0], NULL); - } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) { - // tuple of many items - c_tuple(comp, pns->nodes[0], pns2); - } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) { - // generator expression - compile_comprehension(comp, pns, SCOPE_GEN_EXPR); - } else { - // tuple with 2 items - goto tuple_with_2_items; - } + if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns)) { + // generator expression + compile_comprehension(comp, pns, SCOPE_GEN_EXPR); } else { - // tuple with 2 items - tuple_with_2_items: - c_tuple(comp, MP_PARSE_NODE_NULL, pns); + // tuple with N items + compile_generic_tuple(comp, pns); } } } @@ -2525,31 +2452,13 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t *)pns->nodes[0]; - if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) { - mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t *)pns2->nodes[1]; - if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3b) { - // list of one item, with trailing comma - assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0])); - compile_node(comp, pns2->nodes[0]); - EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST); - } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) { - // list of many items - compile_node(comp, pns2->nodes[0]); - compile_generic_all_nodes(comp, pns3); - EMIT_ARG(build, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3), MP_EMIT_BUILD_LIST); - } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) { - // list comprehension - compile_comprehension(comp, pns2, SCOPE_LIST_COMP); - } else { - // list with 2 items - goto list_with_2_items; - } + if (MP_PARSE_NODE_TESTLIST_COMP_HAS_COMP_FOR(pns2)) { + // list comprehension + compile_comprehension(comp, pns2, SCOPE_LIST_COMP); } else { - // list with 2 items - list_with_2_items: - compile_node(comp, pns2->nodes[0]); - compile_node(comp, pns2->nodes[1]); - EMIT_ARG(build, 2, MP_EMIT_BUILD_LIST); + // list with N items + compile_generic_all_nodes(comp, pns2); + EMIT_ARG(build, MP_PARSE_NODE_STRUCT_NUM_NODES(pns2), MP_EMIT_BUILD_LIST); } } else { // list with 1 item diff --git a/py/dynruntime.mk b/py/dynruntime.mk index cb5ab845e..db06d41e7 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -46,7 +46,6 @@ ifeq ($(ARCH),x86) # x86 CROSS = CFLAGS += -m32 -fno-stack-protector -MPY_CROSS_FLAGS += -mcache-lookup-bc MICROPY_FLOAT_IMPL ?= double else ifeq ($(ARCH),x64) @@ -54,7 +53,6 @@ else ifeq ($(ARCH),x64) # x64 CROSS = CFLAGS += -fno-stack-protector -MPY_CROSS_FLAGS += -mcache-lookup-bc MICROPY_FLOAT_IMPL ?= double else ifeq ($(ARCH),armv7m) diff --git a/py/emitbc.c b/py/emitbc.c index d7e8e05f0..ca7404603 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -560,9 +560,6 @@ void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) { MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL); (void)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_raw_byte(emit, 0); - } } void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) { @@ -596,9 +593,6 @@ void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) { } emit_write_bytecode_byte_qstr(emit, -2, MP_BC_STORE_ATTR, qst); } - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_raw_byte(emit, 0); - } } void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { diff --git a/py/emitnative.c b/py/emitnative.c index 7c7c34283..6504f3776 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1560,6 +1560,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) { int reg_base = REG_ARG_1; int reg_index = REG_ARG_2; emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_index); + need_reg_single(emit, REG_RET, 0); switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory @@ -1623,6 +1624,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) { int reg_index = REG_ARG_2; emit_pre_pop_reg_flexible(emit, &vtype_index, ®_index, REG_ARG_1, REG_ARG_1); emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); + need_reg_single(emit, REG_RET, 0); if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT("can't load with '%q' index"), vtype_to_qstr(vtype_index)); diff --git a/py/frozenmod.c b/py/frozenmod.c index a250c0215..6cb68d1ec 100644 --- a/py/frozenmod.c +++ b/py/frozenmod.c @@ -5,6 +5,7 @@ * * Copyright (c) 2015 Paul Sokolovsky * Copyright (c) 2016 Damien P. George + * Copyright (c) 2021 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 @@ -31,6 +32,13 @@ #include "py/lexer.h" #include "py/frozenmod.h" +#if MICROPY_MODULE_FROZEN + +// Null-separated frozen file names. All string-type entries are listed first, +// followed by mpy-type entries. Use mp_frozen_str_sizes to determine how +// many string entries. +extern const char mp_frozen_names[]; + #if MICROPY_MODULE_FROZEN_STR #ifndef MICROPY_MODULE_FROZEN_LEXER @@ -39,118 +47,89 @@ mp_lexer_t *MICROPY_MODULE_FROZEN_LEXER(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len); #endif -extern const char mp_frozen_str_names[]; +// Size in bytes of each string entry, followed by a zero (terminator). extern const uint32_t mp_frozen_str_sizes[]; +// Null-separated string content. extern const char mp_frozen_str_content[]; - -// On input, *len contains size of name, on output - size of content -const char *mp_find_frozen_str(const char *str, size_t *len) { - const char *name = mp_frozen_str_names; - - size_t offset = 0; - for (int i = 0; *name != 0; i++) { - size_t l = strlen(name); - if (l == *len && !memcmp(str, name, l)) { - *len = mp_frozen_str_sizes[i]; - return mp_frozen_str_content + offset; - } - name += l + 1; - offset += mp_frozen_str_sizes[i] + 1; - } - return NULL; -} - -STATIC mp_lexer_t *mp_lexer_frozen_str(const char *str, size_t len) { - size_t name_len = len; - const char *content = mp_find_frozen_str(str, &len); - - if (content == NULL) { - return NULL; - } - - qstr source = qstr_from_strn(str, name_len); - mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, len, 0); - return lex; -} - -#endif +#endif // MICROPY_MODULE_FROZEN_STR #if MICROPY_MODULE_FROZEN_MPY #include "py/emitglue.h" -extern const char mp_frozen_mpy_names[]; extern const mp_raw_code_t *const mp_frozen_mpy_content[]; -STATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t len) { - const char *name = mp_frozen_mpy_names; - for (size_t i = 0; *name != 0; i++) { - size_t l = strlen(name); - if (l == len && !memcmp(str, name, l)) { - return mp_frozen_mpy_content[i]; - } - name += l + 1; - } - return NULL; -} +#endif // MICROPY_MODULE_FROZEN_MPY -#endif - -#if MICROPY_MODULE_FROZEN - -STATIC mp_import_stat_t mp_frozen_stat_helper(const char *name, const char *str) { +// Search for "str" as a frozen entry, returning the stat result +// (no-exist/file/dir), as well as the type (none/str/mpy) and data. +// frozen_type can be NULL if its value isn't needed (and then data is assumed to be NULL). +mp_import_stat_t mp_find_frozen_module(const char *str, int *frozen_type, void **data) { size_t len = strlen(str); + const char *name = mp_frozen_names; + + if (frozen_type != NULL) { + *frozen_type = MP_FROZEN_NONE; + } + + // Count the number of str lengths we have to find how many str entries. + size_t num_str = 0; + #if MICROPY_MODULE_FROZEN_STR && MICROPY_MODULE_FROZEN_MPY + for (const uint32_t *s = mp_frozen_str_sizes; *s != 0; ++s) { + ++num_str; + } + #endif + + for (size_t i = 0; *name != 0; i++) { + size_t entry_len = strlen(name); + if (entry_len >= len && memcmp(str, name, len) == 0) { + // Query is a prefix of the current entry. + if (entry_len == len) { + // Exact match --> file. + + if (frozen_type != NULL) { + #if MICROPY_MODULE_FROZEN_STR + if (i < num_str) { + *frozen_type = MP_FROZEN_STR; + // Use the size table to figure out where this index starts. + size_t offset = 0; + for (size_t j = 0; j < i; ++j) { + offset += mp_frozen_str_sizes[j] + 1; + } + size_t content_len = mp_frozen_str_sizes[i]; + const char *content = &mp_frozen_str_content[offset]; + + // Note: str & len have been updated by find_frozen_entry to strip + // the ".frozen/" prefix (to avoid this being a distinct qstr to + // the original path QSTR in frozen_content.c). + qstr source = qstr_from_strn(str, len); + mp_lexer_t *lex = MICROPY_MODULE_FROZEN_LEXER(source, content, content_len, 0); + *data = lex; + } + #endif + + #if MICROPY_MODULE_FROZEN_MPY + if (i >= num_str) { + *frozen_type = MP_FROZEN_MPY; + // Load the corresponding index as a raw_code, taking + // into account any string entries to offset by. + *data = (void *)mp_frozen_mpy_content[i - num_str]; + } + #endif + } - for (int i = 0; *name != 0; i++) { - size_t l = strlen(name); - if (l >= len && !memcmp(str, name, len)) { - if (name[len] == 0) { return MP_IMPORT_STAT_FILE; } else if (name[len] == '/') { + // Matches up to directory separator, this is a valid + // directory path. return MP_IMPORT_STAT_DIR; } } - name += l + 1; + // Skip null separator. + name += entry_len + 1; } - return MP_IMPORT_STAT_NO_EXIST; -} - -mp_import_stat_t mp_frozen_stat(const char *str) { - mp_import_stat_t stat; - - #if MICROPY_MODULE_FROZEN_STR - stat = mp_frozen_stat_helper(mp_frozen_str_names, str); - if (stat != MP_IMPORT_STAT_NO_EXIST) { - return stat; - } - #endif - - #if MICROPY_MODULE_FROZEN_MPY - stat = mp_frozen_stat_helper(mp_frozen_mpy_names, str); - if (stat != MP_IMPORT_STAT_NO_EXIST) { - return stat; - } - #endif return MP_IMPORT_STAT_NO_EXIST; } -int mp_find_frozen_module(const char *str, size_t len, void **data) { - #if MICROPY_MODULE_FROZEN_STR - mp_lexer_t *lex = mp_lexer_frozen_str(str, len); - if (lex != NULL) { - *data = lex; - return MP_FROZEN_STR; - } - #endif - #if MICROPY_MODULE_FROZEN_MPY - const mp_raw_code_t *rc = mp_find_frozen_mpy(str, len); - if (rc != NULL) { - *data = (void *)rc; - return MP_FROZEN_MPY; - } - #endif - return MP_FROZEN_NONE; -} - -#endif +#endif // MICROPY_MODULE_FROZEN diff --git a/py/frozenmod.h b/py/frozenmod.h index 8a477d028..be735e85b 100644 --- a/py/frozenmod.h +++ b/py/frozenmod.h @@ -35,8 +35,6 @@ enum { MP_FROZEN_MPY, }; -int mp_find_frozen_module(const char *str, size_t len, void **data); -const char *mp_find_frozen_str(const char *str, size_t *len); -mp_import_stat_t mp_frozen_stat(const char *str); +mp_import_stat_t mp_find_frozen_module(const char *str, int *frozen_type, void **data); #endif // MICROPY_INCLUDED_PY_FROZENMOD_H diff --git a/py/gc.c b/py/gc.c index 8284c435b..a01d81abd 100644 --- a/py/gc.c +++ b/py/gc.c @@ -213,6 +213,7 @@ STATIC void gc_mark_subtree(size_t block) { // Start with the block passed in the argument. size_t sp = 0; for (;;) { + MICROPY_GC_HOOK_LOOP // work out number of consecutive blocks in the chain starting with this one size_t n_blocks = 0; do { @@ -222,6 +223,7 @@ STATIC void gc_mark_subtree(size_t block) { // check this block's children void **ptrs = (void **)PTR_FROM_BLOCK(block); for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void *); i > 0; i--, ptrs++) { + MICROPY_GC_HOOK_LOOP void *ptr = *ptrs; if (VERIFY_PTR(ptr)) { // Mark and push this pointer @@ -255,6 +257,7 @@ STATIC void gc_deal_with_stack_overflow(void) { // scan entire memory looking for blocks which have been marked but not their children for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { + MICROPY_GC_HOOK_LOOP // trace (again) if mark bit set if (ATB_GET_KIND(block) == AT_MARK) { gc_mark_subtree(block); @@ -270,6 +273,7 @@ STATIC void gc_sweep(void) { // free unmarked heads and their tails int free_tail = 0; for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { + MICROPY_GC_HOOK_LOOP switch (ATB_GET_KIND(block)) { case AT_HEAD: #if MICROPY_ENABLE_FINALISER @@ -354,6 +358,7 @@ static void *gc_get_ptr(void **ptrs, int i) { void gc_collect_root(void **ptrs, size_t len) { for (size_t i = 0; i < len; i++) { + MICROPY_GC_HOOK_LOOP void *ptr = gc_get_ptr(ptrs, i); if (VERIFY_PTR(ptr)) { size_t block = BLOCK_FROM_PTR(ptr); diff --git a/py/lexer.c b/py/lexer.c index 69c7d14a7..ac406bd46 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -363,9 +363,16 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) // (MicroPython limitation) note: this is completely unaware of // Python syntax and will not handle any expression containing '}' or ':'. // e.g. f'{"}"}' or f'{foo({})}'. - while (!is_end(lex) && !is_char_or(lex, ':', '}')) { + unsigned int nested_bracket_level = 0; + while (!is_end(lex) && (nested_bracket_level != 0 || !is_char_or(lex, ':', '}'))) { + unichar c = CUR_CHAR(lex); + if (c == '[' || c == '{') { + nested_bracket_level += 1; + } else if (c == ']' || c == '}') { + nested_bracket_level -= 1; + } // like the default case at the end of this function, stay 8-bit clean - vstr_add_byte(&lex->fstring_args, CUR_CHAR(lex)); + vstr_add_byte(&lex->fstring_args, c); next_char(lex); } if (lex->fstring_args.buf[lex->fstring_args.len - 1] == '=') { diff --git a/py/map.c b/py/map.c index 54f4b0204..b194250cb 100644 --- a/py/map.c +++ b/py/map.c @@ -40,6 +40,27 @@ #define DEBUG_printf(...) (void)0 #endif +#if MICROPY_OPT_MAP_LOOKUP_CACHE +// MP_STATE_VM(map_lookup_cache) provides a cache of index to the last known +// position of that index in any map. On a cache hit, this allows +// short-circuiting the full linear search in the case of an ordered map +// (i.e. all builtin modules and objects' locals dicts), and computation of +// the hash (and potentially some linear probing) in the case of a regular +// map. Note the same cache is shared across all maps. + +// Gets the index into the cache for this index. Shift down by two to remove +// mp_obj_t tag bits. +#define MAP_CACHE_OFFSET(index) ((((uintptr_t)(index)) >> 2) % MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE) +// Gets the map cache entry for the corresponding index. +#define MAP_CACHE_ENTRY(index) (MP_STATE_VM(map_lookup_cache)[MAP_CACHE_OFFSET(index)]) +// Retrieve the mp_obj_t at the location suggested by the cache. +#define MAP_CACHE_GET(map, index) (&(map)->table[MAP_CACHE_ENTRY(index) % (map)->alloc]) +// Update the cache for this index. +#define MAP_CACHE_SET(index, pos) MAP_CACHE_ENTRY(index) = (pos) & 0xff; +#else +#define MAP_CACHE_SET(index, pos) +#endif + // This table of sizes is used to control the growth of hash tables. // The first set of sizes are chosen so the allocation fits exactly in a // 4-word GC block, and it's not so important for these small values to be @@ -132,10 +153,22 @@ STATIC void mp_map_rehash(mp_map_t *map) { // - returns slot, with key non-null and value=MP_OBJ_NULL if it was added // MP_MAP_LOOKUP_REMOVE_IF_FOUND behaviour: // - returns NULL if not found, else the slot if was found in with key null and value non-null -mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { +mp_map_elem_t *MICROPY_WRAP_MP_MAP_LOOKUP(mp_map_lookup)(mp_map_t * map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { // If the map is a fixed array then we must only be called for a lookup assert(!map->is_fixed || lookup_kind == MP_MAP_LOOKUP); + #if MICROPY_OPT_MAP_LOOKUP_CACHE + // Try the cache for lookup or add-if-not-found. + if (lookup_kind != MP_MAP_LOOKUP_REMOVE_IF_FOUND && map->alloc) { + mp_map_elem_t *slot = MAP_CACHE_GET(map, index); + // Note: Just comparing key for value equality will have false negatives, but + // these will be handled by the regular path below. + if (slot->key == index) { + return slot; + } + } + #endif + // Work out if we can compare just pointers bool compare_only_ptrs = map->all_keys_are_qstrs; if (compare_only_ptrs) { @@ -172,6 +205,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t elem->value = value; } #endif + MAP_CACHE_SET(index, elem - map->table); return elem; } } @@ -254,6 +288,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t } // keep slot->value so that caller can access it if needed } + MAP_CACHE_SET(index, pos); return slot; } diff --git a/py/mkrules.cmake b/py/mkrules.cmake index 9d0801793..cb5fdabf6 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -10,6 +10,15 @@ set(MICROPY_QSTRDEFS_COLLECTED "${MICROPY_GENHDR_DIR}/qstrdefs.collected.h") set(MICROPY_QSTRDEFS_PREPROCESSED "${MICROPY_GENHDR_DIR}/qstrdefs.preprocessed.h") set(MICROPY_QSTRDEFS_GENERATED "${MICROPY_GENHDR_DIR}/qstrdefs.generated.h") +# Need to do this before extracting MICROPY_CPP_DEF below. Rest of frozen +# manifest handling is at the end of this file. +if(MICROPY_FROZEN_MANIFEST) + target_compile_definitions(${MICROPY_TARGET} PUBLIC + MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool + MICROPY_MODULE_FROZEN_MPY=\(1\) + ) +endif() + # Provide defaults for preprocessor flags if not already defined if(NOT MICROPY_CPP_FLAGS) get_target_property(MICROPY_CPP_INC ${MICROPY_TARGET} INCLUDE_DIRECTORIES) @@ -120,10 +129,7 @@ if(MICROPY_FROZEN_MANIFEST) ${MICROPY_FROZEN_CONTENT} ) - target_compile_definitions(${MICROPY_TARGET} PUBLIC - MICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool - MICROPY_MODULE_FROZEN_MPY=\(1\) - ) + # Note: target_compile_definitions already added earlier. if(NOT MICROPY_LIB_DIR) set(MICROPY_LIB_DIR ${MICROPY_DIR}/../micropython-lib) diff --git a/py/mkrules.mk b/py/mkrules.mk index d0c0a53c2..963d70c2c 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -142,43 +142,18 @@ $(MICROPY_MPYCROSS_DEPENDENCY): $(MAKE) -C $(dir $@) endif +ifneq ($(FROZEN_DIR),) +$(error Support for FROZEN_DIR was removed. Please use manifest.py instead, see https://docs.micropython.org/en/latest/reference/manifest.html) +endif + +ifneq ($(FROZEN_MPY_DIR),) +$(error Support for FROZEN_MPY_DIR was removed. Please use manifest.py instead, see https://docs.micropython.org/en/latest/reference/manifest.html) +endif + ifneq ($(FROZEN_MANIFEST),) # to build frozen_content.c from a manifest $(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY) $(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)",) --mpy-tool-flags="$(MPY_TOOL_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)) - -# to build .mpy files from .py files -$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py | $(MICROPY_MPYCROSS_DEPENDENCY) - @$(ECHO) "MPY $<" - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(MICROPY_MPYCROSS) -o $@ -s $(<:$(FROZEN_MPY_DIR)/%=%) $(MPY_CROSS_FLAGS) $< - -# to build frozen_mpy.c from all .mpy files -$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h - @$(ECHO) "GEN $@" - $(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif ifneq ($(PROG),) @@ -234,27 +209,6 @@ clean: $(RM) -rf $(BUILD) $(CLEAN_EXTRA) .PHONY: clean -# Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup. -# We run rmdir below to avoid empty backup dir (it will silently fail if backup -# is non-empty). -clean-frozen: - if [ -n "$(FROZEN_MPY_DIR)" ]; then \ - backup_dir=$(FROZEN_MPY_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \ - cd $(FROZEN_MPY_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \ - | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \ - rmdir ../$$backup_dir 2>/dev/null || true; \ - git clean -d -f .; \ - fi - - if [ -n "$(FROZEN_DIR)" ]; then \ - backup_dir=$(FROZEN_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \ - cd $(FROZEN_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \ - | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \ - rmdir ../$$backup_dir 2>/dev/null || true; \ - git clean -d -f .; \ - fi -.PHONY: clean-frozen - print-cfg: $(ECHO) "PY_SRC = $(PY_SRC)" $(ECHO) "BUILD = $(BUILD)" diff --git a/py/modbuiltins.c b/py/modbuiltins.c index a7e49a1ed..26a84f57b 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -775,6 +775,7 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { // Extra builtins as defined by a port MICROPY_PORT_BUILTINS + MICROPY_PORT_EXTRA_BUILTINS }; MP_DEFINE_CONST_DICT(mp_module_builtins_globals, mp_module_builtins_globals_table); diff --git a/py/modio.c b/py/modio.c index 7f0d13cdf..e79d59e4e 100644 --- a/py/modio.c +++ b/py/modio.c @@ -204,50 +204,6 @@ STATIC const mp_obj_type_t mp_type_bufwriter = { }; #endif // MICROPY_PY_IO_BUFFEREDWRITER -#if MICROPY_PY_IO_RESOURCE_STREAM -STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { - VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX); - size_t len; - - // As an extension to pkg_resources.resource_stream(), we support - // package parameter being None, the path_in is interpreted as a - // raw path. - if (package_in != mp_const_none) { - // 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); - if (dest[0] == MP_OBJ_NULL) { - mp_raise_TypeError(NULL); - } - - const char *path = mp_obj_str_get_data(dest[0], &len); - vstr_add_strn(&path_buf, path, len); - vstr_add_byte(&path_buf, '/'); - } - - const char *path = mp_obj_str_get_data(path_in, &len); - vstr_add_strn(&path_buf, path, len); - - len = path_buf.len; - const char *data = mp_find_frozen_str(path_buf.buf, &len); - if (data != NULL) { - mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); - o->base.type = &mp_type_bytesio; - o->vstr = m_new_obj(vstr_t); - vstr_init_fixed_buf(o->vstr, len + 1, (char *)data); - o->vstr->len = len; - o->pos = 0; - return MP_OBJ_FROM_PTR(o); - } - - mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len); - return mp_builtin_open(1, &path_out, (mp_map_t *)&mp_const_empty_map); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); -#endif - STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uio) }, // Note: mp_builtin_open_obj should be defined by port, it's not @@ -256,9 +212,6 @@ STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = { #if MICROPY_PY_IO_IOBASE { MP_ROM_QSTR(MP_QSTR_IOBase), MP_ROM_PTR(&mp_type_iobase) }, #endif - #if MICROPY_PY_IO_RESOURCE_STREAM - { MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) }, - #endif #if MICROPY_PY_IO_FILEIO { MP_ROM_QSTR(MP_QSTR_FileIO), MP_ROM_PTR(&mp_type_fileio) }, #if MICROPY_CPYTHON_COMPAT diff --git a/py/modsys.c b/py/modsys.c index 64349f3c3..43666bc00 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -175,7 +175,7 @@ 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. +// settrace(tracefunc): Set the system's trace function. STATIC mp_obj_t mp_sys_settrace(mp_obj_t obj) { return mp_prof_settrace(obj); } diff --git a/py/mpconfig.h b/py/mpconfig.h index 71440da39..c1a0bfc04 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 17 +#define MICROPY_VERSION_MINOR 18 #define MICROPY_VERSION_MICRO 0 // Combined version as a 32-bit number for convenience @@ -62,6 +62,31 @@ #include #endif +// Disable all optional features (i.e. minimal port). +#define MICROPY_CONFIG_ROM_LEVEL_MINIMUM (0) +// Only enable core features (constrained flash, e.g. STM32L072) +#define MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES (10) +// Enable most common features (small on-device flash, e.g. STM32F411) +#define MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES (20) +// Enable convenience features (medium on-device flash, e.g. STM32F405) +#define MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES (30) +// Enable all common features (large/external flash, rp2, unix) +#define MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES (40) +// Enable everything (e.g. coverage) +#define MICROPY_CONFIG_ROM_LEVEL_EVERYTHING (50) + +// Ports/boards should set this, but default to level=core. +#ifndef MICROPY_CONFIG_ROM_LEVEL +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES) +#endif + +// Helper macros for "have at least this level". +#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES) +#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES) +#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) +#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES) +#define MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING (MICROPY_CONFIG_ROM_LEVEL >= MICROPY_CONFIG_ROM_LEVEL_EVERYTHING) + // Any options not explicitly set in mpconfigport.h will get default // values below. @@ -156,7 +181,7 @@ // Support automatic GC when reaching allocation threshold, // configurable by gc.threshold(). #ifndef MICROPY_GC_ALLOC_THRESHOLD -#define MICROPY_GC_ALLOC_THRESHOLD (1) +#define MICROPY_GC_ALLOC_THRESHOLD (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Number of bytes to allocate initially when creating new chunks to store @@ -249,7 +274,11 @@ // Number of bytes used to store qstr hash #ifndef MICROPY_QSTR_BYTES_IN_HASH +#if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES #define MICROPY_QSTR_BYTES_IN_HASH (2) +#else +#define MICROPY_QSTR_BYTES_IN_HASH (1) +#endif #endif // Avoid using C stack when making Python function calls. C stack still @@ -383,7 +412,7 @@ // Whether to include the compiler #ifndef MICROPY_ENABLE_COMPILER -#define MICROPY_ENABLE_COMPILER (1) +#define MICROPY_ENABLE_COMPILER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether the compiler is dynamically configurable (ie at runtime) @@ -394,49 +423,47 @@ // Configure dynamic compiler macros #if MICROPY_DYNAMIC_COMPILER -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC (mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode) #define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC (mp_dynamic_compiler.py_builtins_str_unicode) #else -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE #define MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC MICROPY_PY_BUILTINS_STR_UNICODE #endif // Whether to enable constant folding; eg 1+2 rewritten as 3 #ifndef MICROPY_COMP_CONST_FOLDING -#define MICROPY_COMP_CONST_FOLDING (1) +#define MICROPY_COMP_CONST_FOLDING (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to enable optimisations for constant literals, eg OrderedDict #ifndef MICROPY_COMP_CONST_LITERAL -#define MICROPY_COMP_CONST_LITERAL (1) +#define MICROPY_COMP_CONST_LITERAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to enable lookup of constants in modules; eg module.CONST #ifndef MICROPY_COMP_MODULE_CONST -#define MICROPY_COMP_MODULE_CONST (0) +#define MICROPY_COMP_MODULE_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to enable constant optimisation; id = const(value) #ifndef MICROPY_COMP_CONST -#define MICROPY_COMP_CONST (1) +#define MICROPY_COMP_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to enable optimisation of: a, b = c, d // Costs 124 bytes (Thumb2) #ifndef MICROPY_COMP_DOUBLE_TUPLE_ASSIGN -#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to enable optimisation of: a, b, c = d, e, f // Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2) #ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN -#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to enable optimisation of: return a if b else c // Costs about 80 bytes (Thumb2) and saves 2 bytes of bytecode for each use #ifndef MICROPY_COMP_RETURN_IF_EXPR -#define MICROPY_COMP_RETURN_IF_EXPR (0) +#define MICROPY_COMP_RETURN_IF_EXPR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif /*****************************************************************************/ @@ -491,23 +518,36 @@ #define MICROPY_OPT_COMPUTED_GOTO (0) #endif -// Whether to cache result of map lookups in LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR, -// STORE_ATTR bytecodes. Uses 1 byte extra RAM for each of these opcodes and -// uses a bit of extra code ROM, but greatly improves lookup speed. -#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE -#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0) +// Optimise the fast path for loading attributes from instance types. Increases +// Thumb2 code size by about 48 bytes. +#ifndef MICROPY_OPT_LOAD_ATTR_FAST_PATH +#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + +// Use extra RAM to cache map lookups by remembering the likely location of +// the index. Avoids the hash computation on unordered maps, and avoids the +// linear search on ordered (especially in-ROM) maps. Can provide a +10-15% +// performance improvement on benchmarks involving lots of attribute access +// or dictionary lookup. +#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE +#define MICROPY_OPT_MAP_LOOKUP_CACHE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + +// How much RAM (in bytes) to use for the map lookup cache. +#ifndef MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE +#define MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE (128) #endif // Whether to use fast versions of bitwise operations (and, or, xor) when the // arguments are both positive. Increases Thumb2 code size by about 250 bytes. #ifndef MICROPY_OPT_MPZ_BITWISE -#define MICROPY_OPT_MPZ_BITWISE (0) +#define MICROPY_OPT_MPZ_BITWISE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether math.factorial is large, fast and recursive (1) or small and slow (0). #ifndef MICROPY_OPT_MATH_FACTORIAL -#define MICROPY_OPT_MATH_FACTORIAL (0) +#define MICROPY_OPT_MATH_FACTORIAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif /*****************************************************************************/ @@ -517,7 +557,7 @@ // When disabled, only importing of built-in modules is supported // When enabled, a port must implement mp_import_stat (among other things) #ifndef MICROPY_ENABLE_EXTERNAL_IMPORT -#define MICROPY_ENABLE_EXTERNAL_IMPORT (1) +#define MICROPY_ENABLE_EXTERNAL_IMPORT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to use the POSIX reader for importing files @@ -562,9 +602,14 @@ #define MICROPY_ENABLE_GC (0) #endif +// Hook to run code during time consuming garbage collector operations +#ifndef MICROPY_GC_HOOK_LOOP +#define MICROPY_GC_HOOK_LOOP +#endif + // Whether to enable finalisers in the garbage collector (ie call __del__) #ifndef MICROPY_ENABLE_FINALISER -#define MICROPY_ENABLE_FINALISER (0) +#define MICROPY_ENABLE_FINALISER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to enable a separate allocator for the Python stack. @@ -581,7 +626,7 @@ // Whether to check C stack usage. C stack used for calling Python functions, // etc. Not checking means segfault on overflow. #ifndef MICROPY_STACK_CHECK -#define MICROPY_STACK_CHECK (0) +#define MICROPY_STACK_CHECK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to have an emergency exception buffer @@ -596,7 +641,7 @@ // Whether to provide the mp_kbd_exception object, and micropython.kbd_intr function #ifndef MICROPY_KBD_EXCEPTION -#define MICROPY_KBD_EXCEPTION (0) +#define MICROPY_KBD_EXCEPTION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Prefer to raise KeyboardInterrupt asynchronously (from signal or interrupt @@ -607,7 +652,7 @@ // Whether to include REPL helper function #ifndef MICROPY_HELPER_REPL -#define MICROPY_HELPER_REPL (0) +#define MICROPY_HELPER_REPL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Allow enabling debug prints after each REPL line @@ -617,7 +662,7 @@ // Whether to include emacs-style readline behavior in REPL #ifndef MICROPY_REPL_EMACS_KEYS -#define MICROPY_REPL_EMACS_KEYS (0) +#define MICROPY_REPL_EMACS_KEYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to include emacs-style word movement/kill readline behavior in REPL. @@ -637,7 +682,7 @@ // Whether to implement auto-indent in REPL #ifndef MICROPY_REPL_AUTO_INDENT -#define MICROPY_REPL_AUTO_INDENT (0) +#define MICROPY_REPL_AUTO_INDENT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether port requires event-driven REPL functions @@ -666,7 +711,7 @@ typedef long long mp_longint_impl_t; // Whether to include information in the byte code to determine source // line number (increases RAM usage, but doesn't slow byte code execution) #ifndef MICROPY_ENABLE_SOURCE_LINE -#define MICROPY_ENABLE_SOURCE_LINE (0) +#define MICROPY_ENABLE_SOURCE_LINE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to include doc strings (increases RAM usage) @@ -684,7 +729,13 @@ typedef long long mp_longint_impl_t; #define MICROPY_ERROR_REPORTING_DETAILED (3) #ifndef MICROPY_ERROR_REPORTING +#if MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +#elif MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) +#else +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) +#endif #endif // Whether issue warnings during compiling/execution @@ -740,7 +791,7 @@ typedef double mp_float_t; // TODO: Originally intended as generic category to not // add bunch of once-off options. May need refactoring later #ifndef MICROPY_CPYTHON_COMPAT -#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_CPYTHON_COMPAT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Perform full checks as done by CPython. Disabling this @@ -749,12 +800,12 @@ typedef double mp_float_t; // grave issues (in other words, only user app should be, // affected, not system). #ifndef MICROPY_FULL_CHECKS -#define MICROPY_FULL_CHECKS (1) +#define MICROPY_FULL_CHECKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether POSIX-semantics non-blocking streams are supported #ifndef MICROPY_STREAMS_NON_BLOCK -#define MICROPY_STREAMS_NON_BLOCK (0) +#define MICROPY_STREAMS_NON_BLOCK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide stream functions with POSIX-like signatures @@ -765,17 +816,23 @@ typedef double mp_float_t; // Whether to call __init__ when importing builtin modules for the first time #ifndef MICROPY_MODULE_BUILTIN_INIT -#define MICROPY_MODULE_BUILTIN_INIT (0) +#define MICROPY_MODULE_BUILTIN_INIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support module-level __getattr__ (see PEP 562) #ifndef MICROPY_MODULE_GETATTR -#define MICROPY_MODULE_GETATTR (1) +#define MICROPY_MODULE_GETATTR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether module weak links are supported #ifndef MICROPY_MODULE_WEAK_LINKS -#define MICROPY_MODULE_WEAK_LINKS (0) +#define MICROPY_MODULE_WEAK_LINKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + +// Whether to enable importing foo.py with __name__ set to '__main__' +// Used by the unix port for the -m flag. +#ifndef MICROPY_MODULE_OVERRIDE_MAIN_IMPORT +#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (0) #endif // Whether frozen modules are supported in the form of strings @@ -795,7 +852,7 @@ typedef double mp_float_t; // Whether you can override builtins in the builtins module #ifndef MICROPY_CAN_OVERRIDE_BUILTINS -#define MICROPY_CAN_OVERRIDE_BUILTINS (0) +#define MICROPY_CAN_OVERRIDE_BUILTINS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to check that the "self" argument of a builtin method has the @@ -804,7 +861,7 @@ typedef double mp_float_t; // list.append([], 1). Without this check such calls will have undefined // behaviour (usually segfault) if the first argument is the wrong type. #ifndef MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG -#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to use internally defined errno's (otherwise system provided ones) @@ -819,7 +876,7 @@ typedef double mp_float_t; // Support for internal scheduler #ifndef MICROPY_ENABLE_SCHEDULER -#define MICROPY_ENABLE_SCHEDULER (0) +#define MICROPY_ENABLE_SCHEDULER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Maximum number of entries in the scheduler @@ -849,41 +906,41 @@ typedef double mp_float_t; // inheritance makes some C functions inherently recursive, and adds a bit of // code overhead. #ifndef MICROPY_MULTIPLE_INHERITANCE -#define MICROPY_MULTIPLE_INHERITANCE (1) +#define MICROPY_MULTIPLE_INHERITANCE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to implement attributes on functions #ifndef MICROPY_PY_FUNCTION_ATTRS -#define MICROPY_PY_FUNCTION_ATTRS (0) +#define MICROPY_PY_FUNCTION_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support the descriptors __get__, __set__, __delete__ // This costs some code size and makes load/store/delete of instance // attributes slower for the classes that use this feature #ifndef MICROPY_PY_DESCRIPTORS -#define MICROPY_PY_DESCRIPTORS (0) +#define MICROPY_PY_DESCRIPTORS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support class __delattr__ and __setattr__ methods // This costs some code size and makes store/delete of instance // attributes slower for the classes that use this feature #ifndef MICROPY_PY_DELATTR_SETATTR -#define MICROPY_PY_DELATTR_SETATTR (0) +#define MICROPY_PY_DELATTR_SETATTR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Support for async/await/async for/async with #ifndef MICROPY_PY_ASYNC_AWAIT -#define MICROPY_PY_ASYNC_AWAIT (1) +#define MICROPY_PY_ASYNC_AWAIT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Support for literal string interpolation, f-strings (see PEP 498, Python 3.6+) #ifndef MICROPY_PY_FSTRINGS -#define MICROPY_PY_FSTRINGS (0) +#define MICROPY_PY_FSTRINGS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Support for assignment expressions with := (see PEP 572, Python 3.8+) #ifndef MICROPY_PY_ASSIGN_EXPR -#define MICROPY_PY_ASSIGN_EXPR (1) +#define MICROPY_PY_ASSIGN_EXPR (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Non-standard .pend_throw() method for generators, allowing for @@ -892,7 +949,7 @@ typedef double mp_float_t; // to generator's .send() or .__next__(). (This is useful to implement // async schedulers.) #ifndef MICROPY_PY_GENERATOR_PEND_THROW -#define MICROPY_PY_GENERATOR_PEND_THROW (1) +#define MICROPY_PY_GENERATOR_PEND_THROW (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Issue a warning when comparing str and bytes objects @@ -902,7 +959,7 @@ typedef double mp_float_t; // Whether str object is proper unicode #ifndef MICROPY_PY_BUILTINS_STR_UNICODE -#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_STR_UNICODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to check for valid UTF-8 when converting bytes to str @@ -912,42 +969,42 @@ typedef double mp_float_t; // Whether str.center() method provided #ifndef MICROPY_PY_BUILTINS_STR_CENTER -#define MICROPY_PY_BUILTINS_STR_CENTER (0) +#define MICROPY_PY_BUILTINS_STR_CENTER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether str.count() method provided #ifndef MICROPY_PY_BUILTINS_STR_COUNT -#define MICROPY_PY_BUILTINS_STR_COUNT (1) +#define MICROPY_PY_BUILTINS_STR_COUNT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether str % (...) formatting operator provided #ifndef MICROPY_PY_BUILTINS_STR_OP_MODULO -#define MICROPY_PY_BUILTINS_STR_OP_MODULO (1) +#define MICROPY_PY_BUILTINS_STR_OP_MODULO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether str.partition()/str.rpartition() method provided #ifndef MICROPY_PY_BUILTINS_STR_PARTITION -#define MICROPY_PY_BUILTINS_STR_PARTITION (0) +#define MICROPY_PY_BUILTINS_STR_PARTITION (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether str.splitlines() method provided #ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES -#define MICROPY_PY_BUILTINS_STR_SPLITLINES (0) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support bytearray object #ifndef MICROPY_PY_BUILTINS_BYTEARRAY -#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#define MICROPY_PY_BUILTINS_BYTEARRAY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to support dict.fromkeys() class method #ifndef MICROPY_PY_BUILTINS_DICT_FROMKEYS -#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (1) +#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to support memoryview object #ifndef MICROPY_PY_BUILTINS_MEMORYVIEW -#define MICROPY_PY_BUILTINS_MEMORYVIEW (0) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support memoryview.itemsize attribute @@ -957,39 +1014,39 @@ typedef double mp_float_t; // Whether to support set object #ifndef MICROPY_PY_BUILTINS_SET -#define MICROPY_PY_BUILTINS_SET (1) +#define MICROPY_PY_BUILTINS_SET (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to support slice subscript operators and slice object #ifndef MICROPY_PY_BUILTINS_SLICE -#define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_SLICE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to support slice attribute read access, // i.e. slice.start, slice.stop, slice.step #ifndef MICROPY_PY_BUILTINS_SLICE_ATTRS -#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support the .indices(len) method on slice objects #ifndef MICROPY_PY_BUILTINS_SLICE_INDICES -#define MICROPY_PY_BUILTINS_SLICE_INDICES (0) +#define MICROPY_PY_BUILTINS_SLICE_INDICES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support frozenset object #ifndef MICROPY_PY_BUILTINS_FROZENSET -#define MICROPY_PY_BUILTINS_FROZENSET (0) +#define MICROPY_PY_BUILTINS_FROZENSET (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support property object #ifndef MICROPY_PY_BUILTINS_PROPERTY -#define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_PROPERTY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to implement the start/stop/step attributes (readback) on // the "range" builtin type. Rarely used, and costs ~60 bytes (x86). #ifndef MICROPY_PY_BUILTINS_RANGE_ATTRS -#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to support binary ops [only (in)equality is defined] between range @@ -1007,7 +1064,7 @@ typedef double mp_float_t; // 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) +#define MICROPY_PY_BUILTINS_ROUND_INT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support complete set of special methods for user @@ -1016,7 +1073,7 @@ typedef double mp_float_t; // "Reverse" methods are controlled by // MICROPY_PY_REVERSE_SPECIAL_METHODS below. #ifndef MICROPY_PY_ALL_SPECIAL_METHODS -#define MICROPY_PY_ALL_SPECIAL_METHODS (0) +#define MICROPY_PY_ALL_SPECIAL_METHODS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support all inplace arithmetic operarion methods @@ -1029,17 +1086,17 @@ typedef double mp_float_t; // (__radd__, etc.). Additionally gated by // MICROPY_PY_ALL_SPECIAL_METHODS. #ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS -#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support compile function #ifndef MICROPY_PY_BUILTINS_COMPILE -#define MICROPY_PY_BUILTINS_COMPILE (0) +#define MICROPY_PY_BUILTINS_COMPILE (MICROPY_ENABLE_COMPILER && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support enumerate function(type) #ifndef MICROPY_PY_BUILTINS_ENUMERATE -#define MICROPY_PY_BUILTINS_ENUMERATE (1) +#define MICROPY_PY_BUILTINS_ENUMERATE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to support eval and exec functions @@ -1050,43 +1107,43 @@ typedef double mp_float_t; // Whether to support the Python 2 execfile function #ifndef MICROPY_PY_BUILTINS_EXECFILE -#define MICROPY_PY_BUILTINS_EXECFILE (0) +#define MICROPY_PY_BUILTINS_EXECFILE (MICROPY_ENABLE_COMPILER && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support filter function(type) #ifndef MICROPY_PY_BUILTINS_FILTER -#define MICROPY_PY_BUILTINS_FILTER (1) +#define MICROPY_PY_BUILTINS_FILTER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to support reversed function(type) #ifndef MICROPY_PY_BUILTINS_REVERSED -#define MICROPY_PY_BUILTINS_REVERSED (1) +#define MICROPY_PY_BUILTINS_REVERSED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to define "NotImplemented" special constant #ifndef MICROPY_PY_BUILTINS_NOTIMPLEMENTED -#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (0) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide the built-in input() function. The implementation of this // uses shared/readline, so can only be enabled if the port uses this readline. #ifndef MICROPY_PY_BUILTINS_INPUT -#define MICROPY_PY_BUILTINS_INPUT (0) +#define MICROPY_PY_BUILTINS_INPUT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support min/max functions #ifndef MICROPY_PY_BUILTINS_MIN_MAX -#define MICROPY_PY_BUILTINS_MIN_MAX (1) +#define MICROPY_PY_BUILTINS_MIN_MAX (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Support for calls to pow() with 3 integer arguments #ifndef MICROPY_PY_BUILTINS_POW3 -#define MICROPY_PY_BUILTINS_POW3 (0) +#define MICROPY_PY_BUILTINS_POW3 (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide the help function #ifndef MICROPY_PY_BUILTINS_HELP -#define MICROPY_PY_BUILTINS_HELP (0) +#define MICROPY_PY_BUILTINS_HELP (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Use this to configure the help text shown for help(). It should be a @@ -1097,17 +1154,17 @@ typedef double mp_float_t; // Add the ability to list the available modules when executing help('modules') #ifndef MICROPY_PY_BUILTINS_HELP_MODULES -#define MICROPY_PY_BUILTINS_HELP_MODULES (0) +#define MICROPY_PY_BUILTINS_HELP_MODULES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to set __file__ for imported modules #ifndef MICROPY_PY___FILE__ -#define MICROPY_PY___FILE__ (1) +#define MICROPY_PY___FILE__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to provide mem-info related functions in micropython module #ifndef MICROPY_PY_MICROPYTHON_MEM_INFO -#define MICROPY_PY_MICROPYTHON_MEM_INFO (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide "micropython.stack_use" function @@ -1124,34 +1181,34 @@ typedef double mp_float_t; // underlying code is shared with "bytearray" builtin type, so to // get real savings, it should be disabled too. #ifndef MICROPY_PY_ARRAY -#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_ARRAY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to support slice assignments for array (and bytearray). // This is rarely used, but adds ~0.5K of code. #ifndef MICROPY_PY_ARRAY_SLICE_ASSIGN -#define MICROPY_PY_ARRAY_SLICE_ASSIGN (0) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support attrtuple type (MicroPython extension) // It provides space-efficient tuples with attribute access #ifndef MICROPY_PY_ATTRTUPLE -#define MICROPY_PY_ATTRTUPLE (1) +#define MICROPY_PY_ATTRTUPLE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to provide "collections" module #ifndef MICROPY_PY_COLLECTIONS -#define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to provide "ucollections.deque" type #ifndef MICROPY_PY_COLLECTIONS_DEQUE -#define MICROPY_PY_COLLECTIONS_DEQUE (0) +#define MICROPY_PY_COLLECTIONS_DEQUE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide "collections.OrderedDict" type #ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT -#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide the _asdict function for namedtuple @@ -1161,22 +1218,22 @@ typedef double mp_float_t; // Whether to provide "math" module #ifndef MICROPY_PY_MATH -#define MICROPY_PY_MATH (1) +#define MICROPY_PY_MATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to provide special math functions: math.{erf,erfc,gamma,lgamma} #ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS -#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (0) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide math.factorial function #ifndef MICROPY_PY_MATH_FACTORIAL -#define MICROPY_PY_MATH_FACTORIAL (0) +#define MICROPY_PY_MATH_FACTORIAL (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide math.isclose function #ifndef MICROPY_PY_MATH_ISCLOSE -#define MICROPY_PY_MATH_ISCLOSE (0) +#define MICROPY_PY_MATH_ISCLOSE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide fix for atan2 Inf handling. @@ -1201,12 +1258,12 @@ typedef double mp_float_t; // Whether to provide "cmath" module #ifndef MICROPY_PY_CMATH -#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_CMATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide "gc" module #ifndef MICROPY_PY_GC -#define MICROPY_PY_GC (1) +#define MICROPY_PY_GC (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to return number of collected objects from gc.collect() @@ -1216,28 +1273,17 @@ typedef double mp_float_t; // Whether to provide "io" module #ifndef MICROPY_PY_IO -#define MICROPY_PY_IO (1) +#define MICROPY_PY_IO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to provide "io.IOBase" class to support user streams #ifndef MICROPY_PY_IO_IOBASE -#define MICROPY_PY_IO_IOBASE (0) -#endif - -// Whether to provide "uio.resource_stream()" function with -// the semantics of CPython's pkg_resources.resource_stream() -// (allows to access binary resources in frozen source packages). -// Note that the same functionality can be achieved in "pure -// Python" by prepocessing binary resources into Python source -// and bytecode-freezing it (with a simple helper module available -// e.g. in micropython-lib). -#ifndef MICROPY_PY_IO_RESOURCE_STREAM -#define MICROPY_PY_IO_RESOURCE_STREAM (0) +#define MICROPY_PY_IO_IOBASE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide "io.FileIO" class #ifndef MICROPY_PY_IO_FILEIO -#define MICROPY_PY_IO_FILEIO (0) +#define MICROPY_PY_IO_FILEIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide "io.BytesIO" class @@ -1252,17 +1298,22 @@ typedef double mp_float_t; // Whether to provide "struct" module #ifndef MICROPY_PY_STRUCT -#define MICROPY_PY_STRUCT (1) +#define MICROPY_PY_STRUCT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to provide "sys" module #ifndef MICROPY_PY_SYS -#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) +#endif + +// Whether to initialise "sys.path" and "sys.argv" to their defaults in mp_init() +#ifndef MICROPY_PY_SYS_PATH_ARGV_DEFAULTS +#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (MICROPY_PY_SYS) #endif // Whether to provide "sys.maxsize" constant #ifndef MICROPY_PY_SYS_MAXSIZE -#define MICROPY_PY_SYS_MAXSIZE (0) +#define MICROPY_PY_SYS_MAXSIZE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide "sys.modules" dictionary @@ -1298,18 +1349,18 @@ typedef double mp_float_t; // Whether to provide sys.{stdin,stdout,stderr} objects #ifndef MICROPY_PY_SYS_STDFILES -#define MICROPY_PY_SYS_STDFILES (0) +#define MICROPY_PY_SYS_STDFILES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide sys.{stdin,stdout,stderr}.buffer object // This is implemented per-port #ifndef MICROPY_PY_SYS_STDIO_BUFFER -#define MICROPY_PY_SYS_STDIO_BUFFER (0) +#define MICROPY_PY_SYS_STDIO_BUFFER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide "uerrno" module #ifndef MICROPY_PY_UERRNO -#define MICROPY_PY_UERRNO (0) +#define MICROPY_PY_UERRNO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide the uerrno.errorcode dict @@ -1319,7 +1370,7 @@ typedef double mp_float_t; // Whether to provide "uselect" module (baremetal implementation) #ifndef MICROPY_PY_USELECT -#define MICROPY_PY_USELECT (0) +#define MICROPY_PY_USELECT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to enable the select() function in the "uselect" module (baremetal @@ -1365,11 +1416,11 @@ typedef double mp_float_t; // Extended modules #ifndef MICROPY_PY_UASYNCIO -#define MICROPY_PY_UASYNCIO (0) +#define MICROPY_PY_UASYNCIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif #ifndef MICROPY_PY_UCTYPES -#define MICROPY_PY_UCTYPES (0) +#define MICROPY_PY_UCTYPES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to provide SHORT, INT, LONG, etc. types in addition to @@ -1379,11 +1430,11 @@ typedef double mp_float_t; #endif #ifndef MICROPY_PY_UZLIB -#define MICROPY_PY_UZLIB (0) +#define MICROPY_PY_UZLIB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif #ifndef MICROPY_PY_UJSON -#define MICROPY_PY_UJSON (0) +#define MICROPY_PY_UJSON (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to support the "separators" argument to dump, dumps @@ -1392,7 +1443,7 @@ typedef double mp_float_t; #endif #ifndef MICROPY_PY_URE -#define MICROPY_PY_URE (0) +#define MICROPY_PY_URE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif #ifndef MICROPY_PY_URE_DEBUG @@ -1408,20 +1459,20 @@ typedef double mp_float_t; #endif #ifndef MICROPY_PY_URE_SUB -#define MICROPY_PY_URE_SUB (0) +#define MICROPY_PY_URE_SUB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif #ifndef MICROPY_PY_UHEAPQ -#define MICROPY_PY_UHEAPQ (0) +#define MICROPY_PY_UHEAPQ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif -// Optimized heap queue for relative timestamps +// Optimized heap queue for relative timestamps (only used by uasyncio v2) #ifndef MICROPY_PY_UTIMEQ #define MICROPY_PY_UTIMEQ (0) #endif #ifndef MICROPY_PY_UHASHLIB -#define MICROPY_PY_UHASHLIB (0) +#define MICROPY_PY_UHASHLIB (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif #ifndef MICROPY_PY_UHASHLIB_MD5 @@ -1450,21 +1501,21 @@ typedef double mp_float_t; #endif #ifndef MICROPY_PY_UBINASCII -#define MICROPY_PY_UBINASCII (0) +#define MICROPY_PY_UBINASCII (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Depends on MICROPY_PY_UZLIB #ifndef MICROPY_PY_UBINASCII_CRC32 -#define MICROPY_PY_UBINASCII_CRC32 (0) +#define MICROPY_PY_UBINASCII_CRC32 (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif #ifndef MICROPY_PY_URANDOM -#define MICROPY_PY_URANDOM (0) +#define MICROPY_PY_URANDOM (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif // Whether to include: randrange, randint, choice, random, uniform #ifndef MICROPY_PY_URANDOM_EXTRA_FUNCS -#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif #ifndef MICROPY_PY_MACHINE @@ -1485,13 +1536,26 @@ typedef double mp_float_t; #define MICROPY_PY_MACHINE_I2C (0) #endif +// Whether to provide the "machine.SoftI2C" class +#ifndef MICROPY_PY_MACHINE_SOFTI2C +#define MICROPY_PY_MACHINE_SOFTI2C (0) +#endif + #ifndef MICROPY_PY_MACHINE_SPI #define MICROPY_PY_MACHINE_SPI (0) #endif +// Whether to provide the "machine.SoftSPI" class +#ifndef MICROPY_PY_MACHINE_SOFTSPI +#define MICROPY_PY_MACHINE_SOFTSPI (0) +#endif + #ifndef MICROPY_PY_USSL #define MICROPY_PY_USSL (0) +#endif + // Whether to add finaliser code to ussl objects +#ifndef MICROPY_PY_USSL_FINALISER #define MICROPY_PY_USSL_FINALISER (0) #endif @@ -1500,13 +1564,18 @@ typedef double mp_float_t; #endif #ifndef MICROPY_PY_FRAMEBUF -#define MICROPY_PY_FRAMEBUF (0) +#define MICROPY_PY_FRAMEBUF (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif #ifndef MICROPY_PY_BTREE #define MICROPY_PY_BTREE (0) #endif +// Whether to provide the low-level "_onewire" module +#ifndef MICROPY_PY_ONEWIRE +#define MICROPY_PY_ONEWIRE (0) +#endif + /*****************************************************************************/ /* Hooks for a port to add builtins */ @@ -1515,6 +1584,12 @@ typedef double mp_float_t; #define MICROPY_PORT_BUILTINS #endif +// Additional builtin function definitions for extension by command-line, boards or variants. +// See modbuiltins.c:mp_module_builtins_globals_table for format. +#ifndef MICROPY_PORT_EXTRA_BUILTINS +#define MICROPY_PORT_EXTRA_BUILTINS +#endif + // Additional builtin module definitions - see objmodule.c:mp_builtin_module_table for format. #ifndef MICROPY_PORT_BUILTIN_MODULES #define MICROPY_PORT_BUILTIN_MODULES @@ -1533,6 +1608,30 @@ typedef double mp_float_t; /*****************************************************************************/ /* Hooks for a port to wrap functions with attributes */ +#ifndef MICROPY_WRAP_MP_BINARY_OP +#define MICROPY_WRAP_MP_BINARY_OP(f) f +#endif + +#ifndef MICROPY_WRAP_MP_EXECUTE_BYTECODE +#define MICROPY_WRAP_MP_EXECUTE_BYTECODE(f) f +#endif + +#ifndef MICROPY_WRAP_MP_LOAD_GLOBAL +#define MICROPY_WRAP_MP_LOAD_GLOBAL(f) f +#endif + +#ifndef MICROPY_WRAP_MP_LOAD_NAME +#define MICROPY_WRAP_MP_LOAD_NAME(f) f +#endif + +#ifndef MICROPY_WRAP_MP_MAP_LOOKUP +#define MICROPY_WRAP_MP_MAP_LOOKUP(f) f +#endif + +#ifndef MICROPY_WRAP_MP_OBJ_GET_TYPE +#define MICROPY_WRAP_MP_OBJ_GET_TYPE(f) f +#endif + #ifndef MICROPY_WRAP_MP_SCHED_EXCEPTION #define MICROPY_WRAP_MP_SCHED_EXCEPTION(f) f #endif diff --git a/py/mpstate.h b/py/mpstate.h index 07335bae4..8ece15166 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -44,7 +44,6 @@ #if MICROPY_DYNAMIC_COMPILER 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; uint8_t nlr_buf_num_regs; @@ -154,9 +153,12 @@ typedef struct _mp_state_vm_t { // dictionary for the __main__ module mp_obj_dict_t dict_main; - // these two lists must be initialised per port, after the call to mp_init + #if MICROPY_PY_SYS + // If MICROPY_PY_SYS_PATH_ARGV_DEFAULTS is not enabled then these two lists + // must be initialised after the call to mp_init. mp_obj_list_t mp_sys_path_obj; mp_obj_list_t mp_sys_argv_obj; + #endif // dictionary for overridden builtins #if MICROPY_CAN_OVERRIDE_BUILTINS @@ -231,6 +233,11 @@ typedef struct _mp_state_vm_t { // This is a global mutex used to make the VM/runtime thread-safe. mp_thread_mutex_t gil_mutex; #endif + + #if MICROPY_OPT_MAP_LOOKUP_CACHE + // See mp_map_lookup. + uint8_t map_lookup_cache[MICROPY_OPT_MAP_LOOKUP_CACHE_SIZE]; + #endif } mp_state_vm_t; // This structure holds state that is specific to a given thread. diff --git a/py/mpz.c b/py/mpz.c index 75e1fb1fd..b61997e2f 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -713,6 +713,7 @@ void mpz_set(mpz_t *dest, const mpz_t *src) { void mpz_set_from_int(mpz_t *z, mp_int_t val) { if (val == 0) { + z->neg = 0; z->len = 0; return; } @@ -899,10 +900,6 @@ bool mpz_is_even(const mpz_t *z) { #endif int mpz_cmp(const mpz_t *z1, const mpz_t *z2) { - // to catch comparison of -0 with +0 - if (z1->len == 0 && z2->len == 0) { - return 0; - } int cmp = (int)z2->neg - (int)z1->neg; if (cmp != 0) { return cmp; @@ -1052,7 +1049,9 @@ void mpz_neg_inpl(mpz_t *dest, const mpz_t *z) { if (dest != z) { mpz_set(dest, z); } - dest->neg = 1 - dest->neg; + if (dest->len) { + dest->neg = 1 - dest->neg; + } } /* computes dest = ~z (= -z - 1) @@ -1148,7 +1147,7 @@ void mpz_add_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); } - dest->neg = lhs->neg; + dest->neg = lhs->neg & !!dest->len; } /* computes dest = lhs - rhs @@ -1172,7 +1171,9 @@ void mpz_sub_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { dest->len = mpn_sub(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len); } - if (neg) { + if (dest->len == 0) { + dest->neg = 0; + } else if (neg) { dest->neg = 1 - lhs->neg; } else { dest->neg = lhs->neg; @@ -1484,14 +1485,16 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary? memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t)); + dest_quo->neg = 0; dest_quo->len = 0; mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary? mpz_set(dest_rem, lhs); mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len); + dest_rem->neg &= !!dest_rem->len; // check signs and do Python style modulo if (lhs->neg != rhs->neg) { - dest_quo->neg = 1; + dest_quo->neg = !!dest_quo->len; if (!mpz_is_zero(dest_rem)) { mpz_t mpzone; mpz_init_from_int(&mpzone, -1); diff --git a/py/mpz.h b/py/mpz.h index 425587ee9..d27f57240 100644 --- a/py/mpz.h +++ b/py/mpz.h @@ -91,6 +91,7 @@ typedef int8_t mpz_dbl_dig_signed_t; #define MPZ_NUM_DIG_FOR_LL ((sizeof(long long) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE) typedef struct _mpz_t { + // Zero has neg=0, len=0. Negative zero is not allowed. size_t neg : 1; size_t fixed_dig : 1; size_t alloc : (8 * sizeof(size_t) - 2); @@ -119,7 +120,7 @@ static inline bool mpz_is_zero(const mpz_t *z) { return z->len == 0; } static inline bool mpz_is_neg(const mpz_t *z) { - return z->len != 0 && z->neg != 0; + return z->neg != 0; } int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs); diff --git a/py/obj.c b/py/obj.c index f66a9d183..5255e9655 100644 --- a/py/obj.c +++ b/py/obj.c @@ -37,7 +37,7 @@ #include "py/stackctrl.h" #include "py/stream.h" // for mp_obj_print -const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { +const mp_obj_type_t *MICROPY_WRAP_MP_OBJ_GET_TYPE(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)) { diff --git a/py/obj.h b/py/obj.h index 11918ba17..7730059e6 100644 --- a/py/obj.h +++ b/py/obj.h @@ -551,6 +551,7 @@ struct _mp_obj_type_t { // // dest[0] = MP_OBJ_NULL means load // return: for fail, do nothing + // for fail but continue lookup in locals_dict, dest[1] = MP_OBJ_SENTINEL // for attr, dest[0] = value // for method, dest[0] = method, dest[1] = self // diff --git a/py/objfun.h b/py/objfun.h index 905b5dbca..771bf31a9 100644 --- a/py/objfun.h +++ b/py/objfun.h @@ -39,8 +39,6 @@ typedef struct _mp_obj_fun_bc_t { // 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) - // - a single slot for var args tuple (if it takes them) - // - a single slot for kw args dict (if it takes them) mp_obj_t extra_args[]; } mp_obj_fun_bc_t; diff --git a/py/objmodule.c b/py/objmodule.c index a1f9d9d7f..6b06740e4 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -35,6 +35,10 @@ #include "genhdr/moduledefs.h" +#if MICROPY_MODULE_BUILTIN_INIT +STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj); +#endif + 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); @@ -230,6 +234,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { #if MICROPY_PY_BLUETOOTH { MP_ROM_QSTR(MP_QSTR_ubluetooth), MP_ROM_PTR(&mp_module_ubluetooth) }, #endif + #if MICROPY_PY_UPLATFORM + { MP_ROM_QSTR(MP_QSTR_uplatform), MP_ROM_PTR(&mp_module_uplatform) }, + #endif // extra builtin modules as defined by a port MICROPY_PORT_BUILTIN_MODULES @@ -242,47 +249,56 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); -// 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; - // lookup module - mp_map_elem_t *el = mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); +// Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL. +mp_obj_t mp_module_get_loaded_or_builtin(qstr module_name) { + // First try loaded modules. + mp_map_elem_t *elem = mp_map_lookup(&MP_STATE_VM(mp_loaded_modules_dict).map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); - if (el == NULL) { - // module not found, look for builtin module names - el = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); - if (el == NULL) { + if (!elem) { + #if MICROPY_MODULE_WEAK_LINKS + return mp_module_get_builtin(module_name); + #else + // Otherwise try builtin. + elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + if (!elem) { return MP_OBJ_NULL; } - mp_module_call_init(module_name, el->value); + + #if MICROPY_MODULE_BUILTIN_INIT + // If found, it's a newly loaded built-in, so init it. + mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value); + #endif + #endif } - // module found, return it - return el->value; -} - -void mp_module_register(qstr qst, mp_obj_t module) { - mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; - mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; + return elem->value; } #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; - } - +// Tries to find a loaded module, otherwise attempts to load a builtin, otherwise MP_OBJ_NULL. +mp_obj_t mp_module_get_builtin(qstr module_name) { + // Try builtin. + mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + if (!elem) { + return MP_OBJ_NULL; } - return MP_OBJ_NULL; + + #if MICROPY_MODULE_BUILTIN_INIT + // If found, it's a newly loaded built-in, so init it. + mp_module_call_init(MP_OBJ_NEW_QSTR(module_name), elem->value); + #endif + + return elem->value; } #endif #if MICROPY_MODULE_BUILTIN_INIT -void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { +STATIC void mp_module_register(mp_obj_t module_name, mp_obj_t module) { + mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; + mp_map_lookup(mp_loaded_modules_map, module_name, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; +} + +STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj) { // Look for __init__ and call it if it exists mp_obj_t dest[2]; mp_load_method_maybe(module_obj, MP_QSTR___init__, dest); diff --git a/py/objmodule.h b/py/objmodule.h index fde4fff34..8a82d13fe 100644 --- a/py/objmodule.h +++ b/py/objmodule.h @@ -30,18 +30,9 @@ extern const mp_map_t mp_builtin_module_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 -static inline void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { - (void)module_name; - (void)module_obj; -} +mp_obj_t mp_module_get_loaded_or_builtin(qstr module_name); +#if MICROPY_MODULE_WEAK_LINKS +mp_obj_t mp_module_get_builtin(qstr module_name); #endif #endif // MICROPY_INCLUDED_PY_OBJMODULE_H diff --git a/py/objtype.c b/py/objtype.c index 508bab99d..0977a67ce 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -579,6 +579,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des assert(mp_obj_is_instance_type(mp_obj_get_type(self_in))); mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + // Note: This is fast-path'ed in the VM for the MP_BC_LOAD_ATTR operation. mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); if (elem != NULL) { // object member, always treated as a value diff --git a/py/parse.c b/py/parse.c index ae3fa8ea6..68c761734 100644 --- a/py/parse.c +++ b/py/parse.c @@ -796,9 +796,11 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { #endif STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) { - // optimise away parenthesis around an expression if possible + // Simplify and optimise certain rules, to reduce memory usage and simplify the compiler. if (rule_id == RULE_atom_paren) { - // there should be just 1 arg for this rule + // Remove parenthesis around a single expression if possible. + // This atom_paren rule always has a single argument, and after this + // optimisation that argument is either NULL or testlist_comp. mp_parse_node_t pn = peek_result(parser, 0); if (MP_PARSE_NODE_IS_NULL(pn)) { // need to keep parenthesis for () @@ -808,6 +810,34 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, // parenthesis around a single expression, so it's just the expression return; } + } else if (rule_id == RULE_testlist_comp) { + // The testlist_comp rule can be the sole argument to either atom_parent + // or atom_bracket, for (...) and [...] respectively. + assert(num_args == 2); + mp_parse_node_t pn = peek_result(parser, 0); + if (MP_PARSE_NODE_IS_STRUCT(pn)) { + mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn; + if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3b) { + // tuple of one item, with trailing comma + pop_result(parser); + --num_args; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3c) { + // tuple of many items, convert testlist_comp_3c to testlist_comp + pop_result(parser); + assert(pn == peek_result(parser, 0)); + pns->kind_num_nodes = rule_id | MP_PARSE_NODE_STRUCT_NUM_NODES(pns) << 8; + return; + } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_comp_for) { + // generator expression + } else { + // tuple with 2 items + } + } else { + // tuple with 2 items + } + } else if (rule_id == RULE_testlist_comp_3c) { + // steal first arg of outer testlist_comp rule + ++num_args; } #if MICROPY_COMP_CONST_FOLDING @@ -827,6 +857,10 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, for (size_t i = num_args; i > 0; i--) { pn->nodes[i - 1] = pop_result(parser); } + if (rule_id == RULE_testlist_comp_3c) { + // need to push something non-null to replace stolen first arg of testlist_comp + push_result_node(parser, (mp_parse_node_t)pn); + } push_result_node(parser, (mp_parse_node_t)pn); } diff --git a/py/persistentcode.h b/py/persistentcode.h index 8769ef584..94fc3bf2d 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -41,16 +41,15 @@ #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. +// The feature flag bits encode the compile-time config options that affect +// the generate bytecode. Note: position 0 is now unused +// (formerly MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE). #define MPY_FEATURE_FLAGS ( \ - ((MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) << 0) \ - | ((MICROPY_PY_BUILTINS_STR_UNICODE) << 1) \ + ((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) \ + ((MICROPY_PY_BUILTINS_STR_UNICODE_DYNAMIC) << 1) \ ) // Define the host architecture diff --git a/py/profile.c b/py/profile.c index 054a0f9e6..d0ac99e07 100644 --- a/py/profile.c +++ b/py/profile.c @@ -540,9 +540,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_ 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: @@ -550,9 +547,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_ 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: @@ -560,9 +554,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_ 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: @@ -618,9 +609,6 @@ STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_ 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: diff --git a/py/py.mk b/py/py.mk index e2ace63bd..80e67ee46 100644 --- a/py/py.mk +++ b/py/py.mk @@ -236,11 +236,13 @@ PY_EXTMOD_O_BASENAME = \ extmod/machine_pinbase.o \ extmod/machine_signal.o \ extmod/machine_pulse.o \ + extmod/machine_pwm.o \ extmod/machine_i2c.o \ extmod/machine_spi.o \ extmod/modbluetooth.o \ extmod/modussl_axtls.o \ extmod/modussl_mbedtls.o \ + extmod/moduplatform.o\ extmod/modurandom.o \ extmod/moduselect.o \ extmod/moduwebsocket.o \ @@ -272,16 +274,6 @@ 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 -endif - -# object file for frozen bytecode (frozen .mpy files) -ifneq ($(FROZEN_MPY_DIR),) -PY_O += $(BUILD)/$(BUILD)/frozen_mpy.o -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) diff --git a/py/qstr.c b/py/qstr.c index 69a5d7a72..f2ccdf484 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -175,6 +175,12 @@ STATIC qstr qstr_add(const byte *q_ptr) { #endif qstr_pool_t *pool = m_new_obj_var_maybe(qstr_pool_t, const char *, new_alloc); if (pool == NULL) { + // Keep qstr_last_chunk consistent with qstr_pool_t: qstr_last_chunk is not scanned + // at garbage collection since it's reachable from a qstr_pool_t. And the caller of + // this function expects q_ptr to be stored in a qstr_pool_t so it can be reached + // by the collector. If qstr_pool_t allocation failed, qstr_last_chunk needs to be + // NULL'd. Otherwise it may become a dangling pointer at the next garbage collection. + MP_STATE_VM(qstr_last_chunk) = NULL; QSTR_EXIT(); m_malloc_fail(new_alloc); } diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 5b4e0dc48..405813941 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -60,6 +60,10 @@ Q() Q() Q(utf-8) +#if MICROPY_MODULE_FROZEN +Q(.frozen) +#endif + #if MICROPY_ENABLE_PYSTACK Q(pystack exhausted) #endif diff --git a/py/runtime.c b/py/runtime.c index 27e5bc13e..8c93f539e 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -122,6 +122,15 @@ void mp_init(void) { MP_STATE_VM(vfs_mount_table) = NULL; #endif + #if MICROPY_PY_SYS_PATH_ARGV_DEFAULTS + 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_)); // current dir (or base dir of the script) + #if MICROPY_MODULE_FROZEN + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen)); + #endif + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); + #endif + #if MICROPY_PY_SYS_ATEXIT MP_STATE_VM(sys_exitfunc) = mp_const_none; #endif @@ -157,7 +166,7 @@ void mp_deinit(void) { #endif } -mp_obj_t mp_load_name(qstr qst) { +mp_obj_t MICROPY_WRAP_MP_LOAD_NAME(mp_load_name)(qstr qst) { // logic: search locals, globals, builtins DEBUG_OP_printf("load name %s\n", qstr_str(qst)); // If we're at the outer scope (locals == globals), dispatch to load_global right away @@ -170,7 +179,7 @@ mp_obj_t mp_load_name(qstr qst) { return mp_load_global(qst); } -mp_obj_t mp_load_global(qstr qst) { +mp_obj_t MICROPY_WRAP_MP_LOAD_GLOBAL(mp_load_global)(qstr qst) { // logic: search globals, builtins DEBUG_OP_printf("load global %s\n", qstr_str(qst)); mp_map_elem_t *elem = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); @@ -311,7 +320,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { } } -mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { +mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { DEBUG_OP_printf("binary " UINT_FMT " %q %p %p\n", op, mp_binary_op_method_name[op], lhs, rhs); // TODO correctly distinguish inplace operators for mutable objects @@ -1081,6 +1090,10 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { dest[0] = MP_OBJ_NULL; dest[1] = MP_OBJ_NULL; + // Note: the specific case of obj being an instance type is fast-path'ed in the VM + // for the MP_BC_LOAD_ATTR opcode. Instance types handle type->attr and look up directly + // in their member's map. + // get the type const mp_obj_type_t *type = mp_obj_get_type(obj); @@ -1096,12 +1109,20 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { if (attr == MP_QSTR___next__ && type->iternext != NULL) { dest[0] = MP_OBJ_FROM_PTR(&mp_builtin_next_obj); dest[1] = obj; - - } else if (type->attr != NULL) { + return; + } + if (type->attr != NULL) { // this type can do its own load, so call it type->attr(obj, attr, dest); - - } else if (type->locals_dict != NULL) { + // If type->attr has set dest[1] = MP_OBJ_SENTINEL, we should proceed + // with lookups below (i.e. in locals_dict). If not, return right away. + if (dest[1] != MP_OBJ_SENTINEL) { + return; + } + // Clear the fail flag set by type->attr so it's like it never ran. + dest[1] = MP_OBJ_NULL; + } + if (type->locals_dict != NULL) { // generic method lookup // this is a lookup in the object (ie not class or type) assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now @@ -1110,6 +1131,7 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { if (elem != NULL) { mp_convert_member_lookup(obj, type, elem->value, dest); } + return; } } @@ -1368,8 +1390,10 @@ mp_obj_t mp_make_raise_obj(mp_obj_t o) { // create and return a new exception instance by calling o // TODO could have an option to disable traceback, then builtin exceptions (eg TypeError) // could have const instances in ROM which we return here instead - return mp_call_function_n_kw(o, 0, 0, NULL); - } else if (mp_obj_is_exception_instance(o)) { + o = mp_call_function_n_kw(o, 0, 0, NULL); + } + + if (mp_obj_is_exception_instance(o)) { // o is an instance of an exception, so use it as the exception return o; } else { diff --git a/py/showbc.c b/py/showbc.c index cb81b8835..da8077ecc 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -98,8 +98,8 @@ void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *i // raw bytecode dump size_t prelude_size = ip - mp_showbc_code_start + n_info + n_cell; - mp_printf(print, "Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", - prelude_size, len - prelude_size); + mp_printf(print, "Raw bytecode (code_info_size=%u, bytecode_size=%u):\n", + (unsigned)prelude_size, (unsigned)(len - prelude_size)); for (mp_uint_t i = 0; i < len; i++) { if (i > 0 && i % 16 == 0) { mp_printf(print, "\n"); @@ -208,25 +208,16 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) { case MP_BC_LOAD_NAME: DECODE_QSTR; mp_printf(print, "LOAD_NAME %s", qstr_str(qst)); - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { - mp_printf(print, " (cache=%u)", *ip++); - } break; case MP_BC_LOAD_GLOBAL: DECODE_QSTR; mp_printf(print, "LOAD_GLOBAL %s", qstr_str(qst)); - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { - mp_printf(print, " (cache=%u)", *ip++); - } break; case MP_BC_LOAD_ATTR: DECODE_QSTR; mp_printf(print, "LOAD_ATTR %s", qstr_str(qst)); - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { - mp_printf(print, " (cache=%u)", *ip++); - } break; case MP_BC_LOAD_METHOD: @@ -270,9 +261,6 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) { case MP_BC_STORE_ATTR: DECODE_QSTR; mp_printf(print, "STORE_ATTR %s", qstr_str(qst)); - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { - mp_printf(print, " (cache=%u)", *ip++); - } break; case MP_BC_STORE_SUBSCR: @@ -531,7 +519,8 @@ const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip) { } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) { mp_printf(print, "STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI); } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { - mp_printf(print, "UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI); + mp_uint_t op = ip[-1] - MP_BC_UNARY_OP_MULTI; + mp_printf(print, "UNARY_OP " UINT_FMT " %s", op, qstr_str(mp_unary_op_method_name[op])); } 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; mp_printf(print, "BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op])); diff --git a/py/vm.c b/py/vm.c index bbfc9914e..0289bcfae 100644 --- a/py/vm.c +++ b/py/vm.c @@ -180,30 +180,13 @@ #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: // MP_VM_RETURN_NORMAL, sp valid, return value in *sp // MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp // MP_VM_RETURN_EXCEPTION, exception in state[0] -mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) { +mp_vm_return_kind_t MICROPY_WRAP_MP_EXECUTE_BYTECODE(mp_execute_bytecode)(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) { #define SELECTIVE_EXC_IP (0) #if SELECTIVE_EXC_IP #define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip; } /* stores ip 1 byte past last opcode */ @@ -361,84 +344,46 @@ dispatch_loop: goto load_check; } - #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_LOAD_NAME): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; PUSH(mp_load_name(qst)); DISPATCH(); } - #else - ENTRY(MP_BC_LOAD_NAME): { - MARK_EXC_IP_SELECTIVE(); - DECODE_QSTR; - 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 { - obj = mp_load_name(qst); - } - PUSH(obj); - ip++; - DISPATCH(); - } - #endif - #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_LOAD_GLOBAL): { MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; PUSH(mp_load_global(qst)); DISPATCH(); } - #else - ENTRY(MP_BC_LOAD_GLOBAL): { - MARK_EXC_IP_SELECTIVE(); - DECODE_QSTR; - 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 { - obj = mp_load_global(qst); - } - PUSH(obj); - ip++; - DISPATCH(); - } - #endif - #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)); - DISPATCH(); - } - #else ENTRY(MP_BC_LOAD_ATTR): { FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); + mp_obj_t obj; + #if MICROPY_OPT_LOAD_ATTR_FAST_PATH + // For the specific case of an instance type, it implements .attr + // and forwards to its members map. Attribute lookups on instance + // types are extremely common, so avoid all the other checks and + // calls that normally happen first. 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); - elem = mp_map_cached_lookup(&self->members, qst, (uint8_t*)ip); + elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); } - mp_obj_t obj; - if (elem != NULL) { + if (elem) { obj = elem->value; - } else { + } else + #endif + { obj = mp_load_attr(top, qst); } SET_TOP(obj); - ip++; DISPATCH(); } - #endif ENTRY(MP_BC_LOAD_METHOD): { MARK_EXC_IP_SELECTIVE(); @@ -494,7 +439,6 @@ dispatch_loop: DISPATCH(); } - #if !MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE ENTRY(MP_BC_STORE_ATTR): { FRAME_UPDATE(); MARK_EXC_IP_SELECTIVE(); @@ -503,32 +447,6 @@ dispatch_loop: sp -= 2; DISPATCH(); } - #else - // This caching code works with MICROPY_PY_BUILTINS_PROPERTY and/or - // MICROPY_PY_DESCRIPTORS enabled because if the attr exists in - // self->members then it can't be a property or have descriptors. A - // 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_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); - 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]); - } - sp -= 2; - ip++; - DISPATCH(); - } - #endif ENTRY(MP_BC_STORE_SUBSCR): MARK_EXC_IP_SELECTIVE(); diff --git a/shared/libc/string0.c b/shared/libc/string0.c index 19ad14d0f..a3b268e44 100644 --- a/shared/libc/string0.c +++ b/shared/libc/string0.c @@ -25,7 +25,7 @@ */ #include -#include +#include #define likely(x) __builtin_expect((x), 1) @@ -64,6 +64,13 @@ void *memcpy(void *dst, const void *src, size_t n) { return dst; } +void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen) { + if (len > slen) { + return NULL; + } + return memcpy(dest, src, len); +} + void *memmove(void *dest, const void *src, size_t n) { if (src < dest && (uint8_t*)dest < (const uint8_t*)src + n) { // need to copy backwards diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 006ec096f..5f05c1da3 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -50,20 +50,20 @@ int pyexec_system_exit = 0; STATIC bool repl_display_debugging_info = 0; #endif -#define EXEC_FLAG_PRINT_EOF (1) -#define EXEC_FLAG_ALLOW_DEBUGGING (2) -#define EXEC_FLAG_IS_REPL (4) -#define EXEC_FLAG_SOURCE_IS_RAW_CODE (8) -#define EXEC_FLAG_SOURCE_IS_VSTR (16) -#define EXEC_FLAG_SOURCE_IS_FILENAME (32) -#define EXEC_FLAG_SOURCE_IS_READER (64) +#define EXEC_FLAG_PRINT_EOF (1 << 0) +#define EXEC_FLAG_ALLOW_DEBUGGING (1 << 1) +#define EXEC_FLAG_IS_REPL (1 << 2) +#define EXEC_FLAG_SOURCE_IS_RAW_CODE (1 << 3) +#define EXEC_FLAG_SOURCE_IS_VSTR (1 << 4) +#define EXEC_FLAG_SOURCE_IS_FILENAME (1 << 5) +#define EXEC_FLAG_SOURCE_IS_READER (1 << 6) // parses, compiles and executes the code in the lexer // frees the lexer before returning // EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output // EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code // 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) { +STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, mp_uint_t exec_flags) { int ret = 0; #if MICROPY_REPL_INFO uint32_t start = 0; @@ -135,6 +135,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input if (exec_flags & EXEC_FLAG_PRINT_EOF) { mp_hal_stdout_tx_strn("\x04", 1); } + // check for SystemExit if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // at the moment, the value of SystemExit is unused @@ -674,7 +675,7 @@ int pyexec_file(const char *filename) { int pyexec_file_if_exists(const char *filename) { #if MICROPY_MODULE_FROZEN - if (mp_frozen_stat(filename) == MP_IMPORT_STAT_FILE) { + if (mp_find_frozen_module(filename, NULL, NULL) == MP_IMPORT_STAT_FILE) { return pyexec_frozen_module(filename); } #endif @@ -687,7 +688,8 @@ int pyexec_file_if_exists(const char *filename) { #if MICROPY_MODULE_FROZEN int pyexec_frozen_module(const char *name) { void *frozen_data; - int frozen_type = mp_find_frozen_module(name, strlen(name), &frozen_data); + int frozen_type; + mp_find_frozen_module(name, &frozen_type, &frozen_data); switch (frozen_type) { #if MICROPY_MODULE_FROZEN_STR diff --git a/shared/upytesthelper/upytesthelper.c b/shared/upytesthelper/upytesthelper.c index 326172be6..ce6073242 100644 --- a/shared/upytesthelper/upytesthelper.c +++ b/shared/upytesthelper/upytesthelper.c @@ -94,6 +94,9 @@ void upytest_execute_test(const char *src) { gc_init(heap_start, heap_end); mp_init(); mp_obj_list_init(mp_sys_path, 0); + #if MICROPY_MODULE_FROZEN + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen)); + #endif mp_obj_list_init(mp_sys_argv, 0); nlr_buf_t nlr; diff --git a/tests/basics/int_big_cmp.py b/tests/basics/int_big_cmp.py index 7cb7412bd..d7394d3bc 100644 --- a/tests/basics/int_big_cmp.py +++ b/tests/basics/int_big_cmp.py @@ -1,10 +1,13 @@ # test bignum comparisons i = 1 << 65 +cases = (0, 1, -1, i, -i, i + 1, -(i + 1)) -print(i == 0) -print(i != 0) -print(i < 0) -print(i > 0) -print(i <= 0) -print(i >= 0) +for lhs in cases: + for rhs in cases: + print("{} == {} = {}".format(lhs, rhs, lhs == rhs)) + print("{} != {} = {}".format(lhs, rhs, lhs != rhs)) + print("{} < {} = {}".format(lhs, rhs, lhs < rhs)) + print("{} > {} = {}".format(lhs, rhs, lhs > rhs)) + print("{} <= {} = {}".format(lhs, rhs, lhs <= rhs)) + print("{} >= {} = {}".format(lhs, rhs, lhs >= rhs)) diff --git a/tests/basics/int_big_zeroone.py b/tests/basics/int_big_zeroone.py index 7e0b7a720..81381526b 100644 --- a/tests/basics/int_big_zeroone.py +++ b/tests/basics/int_big_zeroone.py @@ -1,4 +1,4 @@ -# test [0,-0,1,-1] edge cases of bignum +# test [0,1,-1] edge cases of bignum long_zero = (2**64) >> 65 long_neg_zero = -long_zero @@ -13,7 +13,7 @@ print([~c for c in cases]) print([c >> 1 for c in cases]) print([c << 1 for c in cases]) -# comparison of 0/-0/+0 +# comparison of 0 print(long_zero == 0) print(long_neg_zero == 0) print(long_one - 1 == 0) @@ -26,3 +26,40 @@ print(long_neg_zero < 1) print(long_neg_zero < -1) print(long_neg_zero > 1) print(long_neg_zero > -1) + +# generate zeros that involve negative numbers +large = 1 << 70 +large_plus_one = large + 1 +zeros = ( + large - large, + -large + large, + large + -large, + -(large - large), + large - large_plus_one + 1, + -large & (large - large), + -large ^ -large, + -large * (large - large), + (large - large) // -large, + -large // -large_plus_one, + -(large + large) % large, + (large + large) % -large, + -(large + large) % -large, +) +print(zeros) + +# compute arithmetic operations that may have problems with -0 +# (this checks that -0 is never generated in the zeros tuple) +cases = (0, 1, -1) + zeros +for lhs in cases: + print("-{} = {}".format(lhs, -lhs)) + print("~{} = {}".format(lhs, ~lhs)) + print("{} >> 1 = {}".format(lhs, lhs >> 1)) + print("{} << 1 = {}".format(lhs, lhs << 1)) + for rhs in cases: + print("{} == {} = {}".format(lhs, rhs, lhs == rhs)) + print("{} + {} = {}".format(lhs, rhs, lhs + rhs)) + print("{} - {} = {}".format(lhs, rhs, lhs - rhs)) + print("{} * {} = {}".format(lhs, rhs, lhs * rhs)) + print("{} | {} = {}".format(lhs, rhs, lhs | rhs)) + print("{} & {} = {}".format(lhs, rhs, lhs & rhs)) + print("{} ^ {} = {}".format(lhs, rhs, lhs ^ rhs)) diff --git a/tests/basics/string_fstring.py b/tests/basics/string_fstring.py index 4f7225fca..7e8a97fd3 100644 --- a/tests/basics/string_fstring.py +++ b/tests/basics/string_fstring.py @@ -22,6 +22,13 @@ def foo(a, b): return f'{x}{y}{a}{b}' print(foo(7, 8)) +# ':' character within {...} that should not be interpreted as format specifiers. +print(f"a{[0,1,2][0:2]}") +print(f"a{[0,15,2][0:2][-1]:04x}") + +# Nested '{' and '}' characters. +print(f"a{ {0,1,2}}") + # PEP-0498 specifies that '\\' and '#' must be disallowed explicitly, whereas # MicroPython relies on the syntax error as a result of the substitution. diff --git a/tests/basics/subclass_native_exc_new.py b/tests/basics/subclass_native_exc_new.py new file mode 100644 index 000000000..c1bd89a6f --- /dev/null +++ b/tests/basics/subclass_native_exc_new.py @@ -0,0 +1,39 @@ +# test subclassing exceptions and providing __new__ + + +class Dummy(BaseException): + pass + + +class GoodException(BaseException): + def __new__(cls, *args, **kwargs): + print("GoodException __new__") + return Dummy(*args, **kwargs) + + +class BadException(BaseException): + def __new__(cls, *args, **kwargs): + print("BadException __new__") + return 1 + + +try: + raise GoodException("good message") +except BaseException as good: + print(type(good), good.args[0]) + +try: + raise BadException("bad message") +except Exception as bad: + # Should be TypeError 'exceptions must derive from BaseException' + print(type(bad), bad.args[0]) + +try: + + def gen(): + yield + + gen().throw(BadException) +except Exception as genbad: + # Should be TypeError 'exceptions must derive from BaseException' + print(type(genbad), genbad.args[0]) diff --git a/tests/basics/subclass_native_exc_new.py.exp b/tests/basics/subclass_native_exc_new.py.exp new file mode 100644 index 000000000..65709b2cc --- /dev/null +++ b/tests/basics/subclass_native_exc_new.py.exp @@ -0,0 +1,6 @@ +GoodException __new__ + good message +BadException __new__ + exceptions must derive from BaseException +BadException __new__ + exceptions must derive from BaseException diff --git a/tests/basics/sys_path.py b/tests/basics/sys_path.py new file mode 100644 index 000000000..6456e2401 --- /dev/null +++ b/tests/basics/sys_path.py @@ -0,0 +1,16 @@ +# test sys.path + +try: + import usys as sys +except ImportError: + import sys + +# check that this script was executed from a file of the same name +if "__file__" not in globals() or "sys_path.py" not in __file__: + print("SKIP") + raise SystemExit + +# test that sys.path[0] is the directory containing this script +with open(sys.path[0] + "/sys_path.py") as f: + for _ in range(4): + print(f.readline()) diff --git a/tests/cmdline/cmd_parsetree.py.exp b/tests/cmdline/cmd_parsetree.py.exp index cc8ba82c0..bee4fc99d 100644 --- a/tests/cmdline/cmd_parsetree.py.exp +++ b/tests/cmdline/cmd_parsetree.py.exp @@ -78,11 +78,11 @@ arg names: 45 STORE_NAME g 48 LOAD_CONST_OBJ \.\+ 50 LOAD_METHOD format -53 LOAD_NAME b (cache=0) -57 CALL_METHOD n=1 nkw=0 -59 STORE_NAME h -62 LOAD_CONST_NONE -63 RETURN_VALUE +53 LOAD_NAME b +56 CALL_METHOD n=1 nkw=0 +58 STORE_NAME h +61 LOAD_CONST_NONE +62 RETURN_VALUE mem: total=\\d\+, current=\\d\+, peak=\\d\+ stack: \\d\+ out of \\d\+ GC: total: \\d\+, used: \\d\+, free: \\d\+ diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index 325efc7db..22712b79e 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -92,10 +92,10 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): 58 BINARY_OP 27 __add__ \\d\+ STORE_FAST 8 \\d\+ LOAD_FAST 0 -\\d\+ UNARY_OP 1 +\\d\+ UNARY_OP 1 __neg__ \\d\+ STORE_FAST 9 \\d\+ LOAD_FAST 0 -\\d\+ UNARY_OP 3 +\\d\+ UNARY_OP 3 \\d\+ STORE_FAST 10 \\d\+ LOAD_FAST 0 \\d\+ LOAD_DEREF 14 @@ -116,14 +116,14 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ LOAD_DEREF 14 \\d\+ LOAD_FAST 1 \\d\+ BINARY_OP 2 __eq__ -\\d\+ UNARY_OP 3 +\\d\+ UNARY_OP 3 \\d\+ STORE_FAST 10 \\d\+ LOAD_DEREF 14 -\\d\+ LOAD_ATTR c (cache=0) +\\d\+ LOAD_ATTR c \\d\+ STORE_FAST 11 \\d\+ LOAD_FAST 11 \\d\+ LOAD_DEREF 14 -\\d\+ STORE_ATTR c (cache=0) +\\d\+ STORE_ATTR c \\d\+ LOAD_DEREF 14 \\d\+ LOAD_CONST_SMALL_INT 0 \\d\+ LOAD_SUBSCR @@ -233,7 +233,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ LOAD_DEREF 16 \\d\+ POP_TOP \\d\+ JUMP \\d\+ -\\d\+ LOAD_GLOBAL y (cache=0) +\\d\+ LOAD_GLOBAL y \\d\+ POP_TOP \\d\+ JUMP \\d\+ \\d\+ LOAD_DEREF 14 @@ -418,13 +418,13 @@ arg names: (N_EXC_STACK 0) bc=0 line=1 ######## - bc=13 line=150 -00 LOAD_NAME __name__ (cache=0) -04 STORE_NAME __module__ -07 LOAD_CONST_STRING 'Class' -10 STORE_NAME __qualname__ -13 LOAD_CONST_NONE -14 RETURN_VALUE + bc=12 line=150 +00 LOAD_NAME __name__ +03 STORE_NAME __module__ +06 LOAD_CONST_STRING 'Class' +09 STORE_NAME __qualname__ +12 LOAD_CONST_NONE +13 RETURN_VALUE File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): ######## @@ -434,8 +434,8 @@ arg names: self (N_EXC_STACK 0) bc=0 line=1 bc=0 line=157 -00 LOAD_GLOBAL super (cache=0) -\\d\+ LOAD_GLOBAL __class__ (cache=0) +00 LOAD_GLOBAL super +\\d\+ LOAD_GLOBAL __class__ \\d\+ LOAD_FAST 0 \\d\+ LOAD_SUPER_METHOD f \\d\+ CALL_METHOD n=0 nkw=0 diff --git a/tests/cmdline/cmd_verbose.py.exp b/tests/cmdline/cmd_verbose.py.exp index a2fdf1f00..0edd050c2 100644 --- a/tests/cmdline/cmd_verbose.py.exp +++ b/tests/cmdline/cmd_verbose.py.exp @@ -8,12 +8,12 @@ arg names: (N_EXC_STACK 0) bc=0 line=1 bc=0 line=3 -00 LOAD_NAME print (cache=0) -04 LOAD_CONST_SMALL_INT 1 -05 CALL_FUNCTION n=1 nkw=0 -07 POP_TOP -08 LOAD_CONST_NONE -09 RETURN_VALUE +00 LOAD_NAME print +03 LOAD_CONST_SMALL_INT 1 +04 CALL_FUNCTION n=1 nkw=0 +06 POP_TOP +07 LOAD_CONST_NONE +08 RETURN_VALUE 1 mem: total=\\d\+, current=\\d\+, peak=\\d\+ stack: \\d\+ out of \\d\+ diff --git a/tests/cpydiff/core_fstring_concat.py b/tests/cpydiff/core_fstring_concat.py index fd83527b5..c2bdb4e66 100644 --- a/tests/cpydiff/core_fstring_concat.py +++ b/tests/cpydiff/core_fstring_concat.py @@ -1,12 +1,13 @@ """ categories: Core -description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces +description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces or are f-strings cause: MicroPython is optimised for code space. -workaround: Use the + operator between literal strings when either is an f-string +workaround: Use the + operator between literal strings when either or both are f-strings """ -x = 1 -print("aa" f"{x}") -print(f"{x}" "ab") -print("a{}a" f"{x}") -print(f"{x}" "a{}b") +x, y = 1, 2 +print("aa" f"{x}") # works +print(f"{x}" "ab") # works +print("a{}a" f"{x}") # fails +print(f"{x}" "a{}b") # fails +print(f"{x}" f"{y}") # fails diff --git a/tests/cpydiff/core_fstring_parser.py b/tests/cpydiff/core_fstring_parser.py index 6917f3cfa..22bbc5866 100644 --- a/tests/cpydiff/core_fstring_parser.py +++ b/tests/cpydiff/core_fstring_parser.py @@ -1,9 +1,9 @@ """ categories: Core -description: f-strings cannot support expressions that require parsing to resolve nested braces +description: f-strings cannot support expressions that require parsing to resolve unbalanced nested braces and brackets cause: MicroPython is optimised for code space. -workaround: Only use simple expressions inside f-strings +workaround: Always use balanced braces and brackets in expressions inside f-strings """ -f'{"hello {} world"}' -f"{repr({})}" +print(f'{"hello { world"}') +print(f'{"hello ] world"}') diff --git a/tests/extmod/uasyncio_gather.py b/tests/extmod/uasyncio_gather.py index 0e2948b07..6053873db 100644 --- a/tests/extmod/uasyncio_gather.py +++ b/tests/extmod/uasyncio_gather.py @@ -22,8 +22,9 @@ async def factorial(name, number): async def task(id): print("start", id) - await asyncio.sleep(0.2) + await asyncio.sleep(0.02) print("end", id) + return id async def gather_task(): @@ -36,12 +37,17 @@ async def main(): # Simple gather with return values print(await asyncio.gather(factorial("A", 2), factorial("B", 3), factorial("C", 4))) + # Test return_exceptions, where one task is cancelled and the other finishes normally + tasks = [asyncio.create_task(task(1)), asyncio.create_task(task(2))] + tasks[0].cancel() + print(await asyncio.gather(*tasks, return_exceptions=True)) + # Cancel a multi gather # TODO doesn't work, Task should not forward cancellation from gather to sub-task # but rather CancelledError should cancel the gather directly, which will then cancel # all sub-tasks explicitly # t = asyncio.create_task(gather_task()) - # await asyncio.sleep(0.1) + # await asyncio.sleep(0.01) # t.cancel() # await asyncio.sleep(0.01) diff --git a/tests/extmod/uasyncio_gather.py.exp b/tests/extmod/uasyncio_gather.py.exp index a37578d7e..95310bbe1 100644 --- a/tests/extmod/uasyncio_gather.py.exp +++ b/tests/extmod/uasyncio_gather.py.exp @@ -8,3 +8,6 @@ Task B: factorial(3) = 6 Task C: Compute factorial(4)... Task C: factorial(4) = 24 [2, 6, 24] +start 2 +end 2 +[CancelledError(), 2] diff --git a/tests/extmod/uselect_poll_udp.py b/tests/extmod/uselect_poll_udp.py index f6be262ee..2a56a122b 100644 --- a/tests/extmod/uselect_poll_udp.py +++ b/tests/extmod/uselect_poll_udp.py @@ -5,7 +5,9 @@ try: except ImportError: try: import socket, select - except ImportError: + + select.poll # Raises AttributeError for CPython implementations without poll() + except (ImportError, AttributeError): print("SKIP") raise SystemExit diff --git a/tests/extmod/utimeq1.py b/tests/extmod/utimeq1.py index 234d7a31d..ddbc969af 100644 --- a/tests/extmod/utimeq1.py +++ b/tests/extmod/utimeq1.py @@ -17,7 +17,6 @@ if DEBUG: def dprint(*v): print(*v) - else: def dprint(*v): diff --git a/tests/io/resource_stream.py b/tests/io/resource_stream.py deleted file mode 100644 index b589ff99b..000000000 --- a/tests/io/resource_stream.py +++ /dev/null @@ -1,15 +0,0 @@ -import uio -import usys - -try: - uio.resource_stream -except AttributeError: - print("SKIP") - raise SystemExit - -buf = uio.resource_stream("data", "file2") -print(buf.read()) - -# resource_stream(None, ...) look ups from current dir, hence sys.path[0] hack -buf = uio.resource_stream(None, usys.path[0] + "/data/file2") -print(buf.read()) diff --git a/tests/io/resource_stream.py.exp b/tests/io/resource_stream.py.exp deleted file mode 100644 index 75404a347..000000000 --- a/tests/io/resource_stream.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -1234 -1234 diff --git a/tests/micropython/const.py b/tests/micropython/const.py index 1faf22be9..1c805a45f 100644 --- a/tests/micropython/const.py +++ b/tests/micropython/const.py @@ -1,4 +1,5 @@ # test constant optimisation +# This test will only work when MICROPY_COMP_CONST is enabled. from micropython import const diff --git a/tests/micropython/import_mpy_native_gc.py b/tests/micropython/import_mpy_native_gc.py index e8fac8f17..f982a4ee1 100644 --- a/tests/micropython/import_mpy_native_gc.py +++ b/tests/micropython/import_mpy_native_gc.py @@ -48,8 +48,8 @@ class UserFS: # Pre-compiled examples/natmod/features0 example for various architectures, keyed # by the required value of sys.implementation.mpy. features0_file_contents = { - # -march=x64 -mcache-lookup-bc - 0xB05: b'M\x05\x0b\x1f \x84b\xe9/\x00\x00\x00SH\x8b\x1ds\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dA\x00\x00\x00H\x8b\x7f\x08L\x8bc(A\xff\xd4H\x8d5\x1f\x00\x00\x00H\x89\xc5H\x8b\x05-\x00\x00\x00\x0f\xb78\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x84@\x12factorial\x10\x00\x00\r \x01"\x9f\x1c\x01\x1e\xff', + # -march=x64 + 0xA05: b'M\x05\x0a\x1f \x84b\xe9/\x00\x00\x00SH\x8b\x1ds\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6ATUSH\x8b\x1dA\x00\x00\x00H\x8b\x7f\x08L\x8bc(A\xff\xd4H\x8d5\x1f\x00\x00\x00H\x89\xc5H\x8b\x05-\x00\x00\x00\x0f\xb78\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x84@\x12factorial\x10\x00\x00\r \x01"\x9f\x1c\x01\x1e\xff', # -march=armv7m 0x1605: b"M\x05\x16\x1f \x84\x12\x1a\xe0\x00\x00\x13\xb5\nK\nJ{D\x9cX\x02!\xe3h\x98G\x03F\x01 3\xb9\x02!#i\x01\x93\x02\xb0\xbd\xe8\x10@\x18GXC\x01;\xf4\xe7\x00\xbfj\x00\x00\x00\x00\x00\x00\x00\xf8\xb5\tN\tK~D\xf4X@hgi\xb8G\x05F\x07K\x07I\xf2XyD\x10\x88ck\x98G(F\xb8G h\xf8\xbd6\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x01\x84\x00\x12factorial\x10\x00\x00\r<\x01>\x9f8\x01:\xff", } diff --git a/tests/micropython/import_mpy_native_x64.py b/tests/micropython/import_mpy_native_x64.py index 3e7b2058e..cad59e991 100644 --- a/tests/micropython/import_mpy_native_x64.py +++ b/tests/micropython/import_mpy_native_x64.py @@ -52,11 +52,11 @@ class UserFS: # fmt: off user_files = { # bad architecture - '/mod0.mpy': b'M\x05\xff\x00\x10', + '/mod0.mpy': b'M\x05\xfe\x00\x10', # test loading of viper and asm '/mod1.mpy': ( - b'M\x05\x0b\x1f\x20' # header + b'M\x05\x0a\x1f\x20' # header b'\x20' # n bytes, bytecode b'\x00\x08\x02m\x02m' # prelude @@ -78,7 +78,7 @@ user_files = { # test loading viper with additional scope flags and relocation '/mod2.mpy': ( - b'M\x05\x0b\x1f\x20' # header + b'M\x05\x0a\x1f\x20' # header b'\x20' # n bytes, bytecode b'\x00\x08\x02m\x02m' # prelude diff --git a/tests/micropython/viper_subscr_multi.py b/tests/micropython/viper_subscr_multi.py new file mode 100644 index 000000000..1561e5534 --- /dev/null +++ b/tests/micropython/viper_subscr_multi.py @@ -0,0 +1,20 @@ +# test viper with multiple subscripts in a single expression + + +@micropython.viper +def f1(b: ptr8): + b[0] += b[1] + + +@micropython.viper +def f2(b: ptr8, i: int): + b[0] += b[i] + + +b = bytearray(b"\x01\x02") +f1(b) +print(b) + +b = bytearray(b"\x01\x02") +f2(b, 1) +print(b) diff --git a/tests/micropython/viper_subscr_multi.py.exp b/tests/micropython/viper_subscr_multi.py.exp new file mode 100644 index 000000000..a2c298bb1 --- /dev/null +++ b/tests/micropython/viper_subscr_multi.py.exp @@ -0,0 +1,2 @@ +bytearray(b'\x03\x02') +bytearray(b'\x03\x02') diff --git a/tests/perf_bench/bm_fft.py b/tests/perf_bench/bm_fft.py index fb79a9fd2..9a2d03d11 100644 --- a/tests/perf_bench/bm_fft.py +++ b/tests/perf_bench/bm_fft.py @@ -15,7 +15,7 @@ def transform_radix2(vector, inverse): # Initialization n = len(vector) - levels = int(math.log2(n)) + levels = int(math.log(n) / math.log(2)) 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 diff --git a/tests/run-tests.py b/tests/run-tests.py index 3e97a7c87..6f3c09d1d 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -742,9 +742,7 @@ the last matching regex is used: 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("--mpy-cross-flags", default="", help="flags to pass to mpy-cross") cmd_parser.add_argument( "--keep-path", action="store_true", help="do not clear MICROPYPATH when running tests" ) @@ -854,7 +852,7 @@ the last matching regex is used: if not args.keep_path: # clear search path to make sure tests use only builtin modules and those in extmod - os.environ["MICROPYPATH"] = os.pathsep + base_path("../extmod") + os.environ["MICROPYPATH"] = ".frozen" + os.pathsep + base_path("../extmod") try: os.makedirs(args.result_dir, exist_ok=True) diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py index b4808993a..8ea27cbf2 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -89,12 +89,6 @@ try: except ZeroDivisionError: print("ZeroDivisionError") -# test loading a resource from a frozen string -import uio - -buf = uio.resource_stream("frzstr_pkg2", "mod.py") -print(buf.read(21)) - # test for MP_QSTR_NULL regression from frzqstr import returns_NULL diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index ea91813fc..8ee233a71 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -174,5 +174,4 @@ frzstr_pkg2.mod frzmpy_pkg2.mod 1 ZeroDivisionError -b'# test frozen package' NULL diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh index a14c7890f..6ac97373f 100755 --- a/tools/autobuild/autobuild.sh +++ b/tools/autobuild/autobuild.sh @@ -5,7 +5,7 @@ # Requirements: # - All toolchains must be in path (arm-none-eabi-gcc, xtensa-lx106-elf) # - IDF_PATH_V42 must be set -# - IDF_PATH_V43 must be set +# - IDF_PATH_V44 must be set # - MICROPY_AUTOBUILD_MICROPYTHON_REPO must be set to location of micropython repository # - MICROPY_AUTOBUILD_MAKE must be set to the make command to use, eg "make -j2" # @@ -18,8 +18,8 @@ if [ ! -d "$IDF_PATH_V42" ]; then exit 1 fi -if [ ! -d "$IDF_PATH_V43" ]; then - echo "must set IDF_PATH_V43" +if [ ! -d "$IDF_PATH_V44" ]; then + echo "must set IDF_PATH_V44" exit 1 fi @@ -39,6 +39,9 @@ fi # get directory of this script for access to other build scripts AUTODIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +# source additional functions +source ${AUTODIR}/build-boards.sh + # make local directory to put firmware LOCAL_FIRMWARE=/tmp/autobuild-firmware-$$ mkdir -p ${LOCAL_FIRMWARE} @@ -62,19 +65,22 @@ FW_GIT="$(git describe --dirty || echo unknown)" FW_TAG="-$FW_DATE-unstable-$FW_GIT" # build new firmware -cd ports/stm32 -${AUTODIR}/build-stm32-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE} -cd ../cc3200 +cd ports/cc3200 ${AUTODIR}/build-cc3200-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE} cd ../esp8266 ${AUTODIR}/build-esp8266-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE} cd ../esp32 -${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V42} ${FW_TAG} ${LOCAL_FIRMWARE} -${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V43} ${FW_TAG} ${LOCAL_FIRMWARE} -cd ../rp2 -${AUTODIR}/build-rp2-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE} +(source ${IDF_PATH_V42}/export.sh && build_esp32_boards ${FW_TAG} ${LOCAL_FIRMWARE}) +(source ${IDF_PATH_V44}/export.sh && build_esp32_boards ${FW_TAG} ${LOCAL_FIRMWARE}) cd ../mimxrt -${AUTODIR}/build-mimxrt-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE} +build_mimxrt_boards ${FW_TAG} ${LOCAL_FIRMWARE} +cd ../rp2 +build_rp2_boards ${FW_TAG} ${LOCAL_FIRMWARE} +cd ../samd +build_samd_boards ${FW_TAG} ${LOCAL_FIRMWARE} +cd ../stm32 +build_stm32_boards ${FW_TAG} ${LOCAL_FIRMWARE} +${AUTODIR}/build-stm32-extra.sh ${FW_TAG} ${LOCAL_FIRMWARE} popd diff --git a/tools/autobuild/build-boards.sh b/tools/autobuild/build-boards.sh new file mode 100755 index 000000000..4b5259b66 --- /dev/null +++ b/tools/autobuild/build-boards.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# +# The functions in this file can be run independently to build boards. +# For example: +# +# $ source build-boards.sh +# $ MICROPY_AUTOBUILD_MAKE=make build_rp2_boards -latest /tmp + +function build_board { + # check/get parameters + if [ $# -lt 4 ]; then + echo "usage: $0 " + return 1 + fi + + board_json=$1 + fw_tag=$2 + dest_dir=$3 + shift + shift + shift + + board=$(echo $board_json | awk -F '/' '{ print $2 }') + descr=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('id', '$board'))") + build_dir=/tmp/micropython-build-$board + + echo "building $descr $board" + $MICROPY_AUTOBUILD_MAKE BOARD=$board BUILD=$build_dir && ( + for ext in $@; do + dest=$dest_dir/$descr$fw_tag.$ext + if [ -r $build_dir/firmware.$ext ]; then + mv $build_dir/firmware.$ext $dest + else + # esp32 has micropython.elf and micropython.map + mv $build_dir/micropython.$ext $dest + fi + done + ) + rm -rf $build_dir +} + +function build_boards { + # check/get parameters + if [ $# -lt 4 ]; then + echo "usage: $0 " + return 1 + fi + + check_file=$1 + shift + + # check we are in the correct directory + if [ ! -r $check_file ]; then + echo "must be in directory containing $check_file" + return 1 + fi + + # build all boards that have a board.json file + for board_json in $(find boards/ -name board.json | sort); do + build_board $board_json $@ + done +} + +function build_esp32_boards { + # check/get parameters + if [ $# != 2 ]; then + echo "usage: $0 " + return 1 + fi + + fw_tag=$1 + dest_dir=$2 + + # check we are in the correct directory + if [ ! -r modesp32.c ]; then + echo "must be in esp32 directory" + return 1 + fi + + # build the boards, based on the IDF version + for board_json in $(find boards/ -name board.json | sort); do + mcu=$(cat $board_json | python3 -c "import json,sys; print(json.load(sys.stdin).get('mcu', 'unknown'))") + if idf.py --version | grep -q v4.2; then + if [ $mcu = esp32 ]; then + # build standard esp32-based boards with IDF v4.2 + if echo $board_json | grep -q GENERIC; then + # traditionally, GENERIC and GENERIC_SPIRAM boards used manifest_release.py + MICROPY_AUTOBUILD_MAKE="$MICROPY_AUTOBUILD_MAKE FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py" build_board $board_json $fw_tag $dest_dir bin elf map + else + build_board $board_json $fw_tag $dest_dir bin elf map + fi + fi + else + if [ $mcu != esp32 ]; then + # build esp32-s2/s3/c3 based boards with IDF v4.4+ + build_board $board_json $fw_tag $dest_dir bin elf map + fi + fi + done +} + +function build_mimxrt_boards { + build_boards modmimxrt.c $1 $2 bin hex +} + +function build_rp2_boards { + build_boards modrp2.c $1 $2 uf2 +} + +function build_samd_boards { + build_boards samd_soc.c $1 $2 uf2 +} + +function build_stm32_boards { + build_boards modpyb.c $1 $2 dfu hex +} diff --git a/tools/autobuild/build-downloads.py b/tools/autobuild/build-downloads.py new file mode 100755 index 000000000..0f532e8bf --- /dev/null +++ b/tools/autobuild/build-downloads.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 + +import glob +import json +import os +import sys + + +def main(repo_path, output_path): + boards_index = [] + board_ids = set() + + for board_json in glob.glob(os.path.join(repo_path, "ports/*/boards/*/board.json")): + # Relative path to the board directory (e.g. "ports/stm32/boards/PYBV11"). + board_dir = os.path.dirname(board_json) + # Relative path to the port (e.g. "ports/stm32") + port_dir = os.path.dirname(os.path.dirname(board_dir)) + + with open(board_json, "r") as f: + blob = json.load(f) + + # Use "id" if specified, otherwise default to board dir (e.g. "PYBV11"). + # We allow boards to override ID for the historical build names. + blob["id"] = blob.get("id", os.path.basename(board_dir)) + + # Check for duplicate board IDs. + if blob["id"] in board_ids: + print("Duplicate board ID: '{}'".format(blob["id"]), file=sys.stderr) + board_ids.add(blob["id"]) + + # Add in default fields. + blob["port"] = os.path.basename(port_dir) + blob["build"] = os.path.basename(board_dir) + boards_index.append(blob) + + # Create the board markdown, which is the concatenation of the + # default "board.md" file (if exists), as well as any flashing + # instructions. + board_markdown = os.path.join(board_dir, "board.md") + with open(os.path.join(output_path, blob["id"] + ".md"), "w") as f: + if os.path.exists(board_markdown): + with open(board_markdown, "r") as fin: + f.write(fin.read()) + + if blob["deploy"]: + f.write("\n\n## Installation instructions\n") + for deploy in blob["deploy"]: + with open(os.path.join(board_dir, deploy), "r") as fin: + f.write(fin.read()) + + # Write the full index for the website to load. + with open(os.path.join(output_path, "index.json"), "w") as f: + json.dump(boards_index, f, indent=4, sort_keys=True) + f.write("\n") + + +if __name__ == "__main__": + main(sys.argv[1], sys.argv[2]) diff --git a/tools/autobuild/build-esp32-latest.sh b/tools/autobuild/build-esp32-latest.sh deleted file mode 100755 index 92a12b2d5..000000000 --- a/tools/autobuild/build-esp32-latest.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -# -# Build esp32 port - -# for debugging -#exec &> /tmp/esp-log-$$.txt - -# function for building firmware -function do_build() { - descr=$1 - board=$2 - shift - shift - echo "building $descr $board" - build_dir=/tmp/esp32-build-$board - rm -rf $build_dir # be sure we don't have anything leftover from a previous build - make $@ BOARD=$board BUILD=$build_dir || exit 1 - mv $build_dir/firmware.bin $dest_dir/$descr$fw_tag.bin - mv $build_dir/micropython.elf $dest_dir/$descr$fw_tag.elf - mv $build_dir/micropython.map $dest_dir/$descr$fw_tag.map - rm -rf $build_dir -} - -# check/get parameters -if [ $# != 3 ]; then - echo "usage: $0 " - exit 1 -fi - -idf_path=$1 -fw_tag=$2 -dest_dir=$3 - -# check we are in the correct directory -if [ ! -r modesp32.c ]; then - echo "must be in esp32 directory" - exit 1 -fi - -source $idf_path/export.sh - -# build the boards, based on the IDF version -if idf.py --version | grep -q v4.2; then - do_build esp32 GENERIC FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py - do_build esp32spiram GENERIC_SPIRAM FROZEN_MANIFEST=$(pwd)/boards/manifest_release.py - do_build tinypico UM_TINYPICO - do_build wesp32 SIL_WESP32 -else - do_build esp32c3 GENERIC_C3 - do_build tinys2 UM_TINYS2 - do_build featherS2 UM_FEATHERS2 -fi diff --git a/tools/autobuild/build-esp8266-latest.sh b/tools/autobuild/build-esp8266-latest.sh index fe79587fd..1972e85fc 100755 --- a/tools/autobuild/build-esp8266-latest.sh +++ b/tools/autobuild/build-esp8266-latest.sh @@ -13,9 +13,7 @@ function do_build() { shift shift echo "building $descr $board" - #build_dir=/tmp/esp8266-build-$board - build_dir=build-$board # until esp8266.ld is fixed - rm -rf $build_dir # be sure we don't have anything leftover from a previous build + build_dir=/tmp/esp8266-build-$board $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1 mv $build_dir/firmware-combined.bin $dest_dir/$descr$fw_tag.bin mv $build_dir/firmware.elf $dest_dir/$descr$fw_tag.elf @@ -29,19 +27,16 @@ function do_build_ota() { shift shift echo "building $descr $board" - #build_dir=/tmp/esp8266-build-$board - build_dir=build-$board # until esp8266.ld is fixed - rm -rf $build_dir # be sure we don't have anything leftover from a previous build + build_dir=/tmp/esp8266-build-$board $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1 cat $yaota8266/yaota8266.bin $build_dir/firmware-ota.bin > $dest_dir/$descr$fw_tag.bin - cwd=$(pwd) pushd $yaota8266/ota-client - $PYTHON3 ota_client.py sign $cwd/$build_dir/firmware-ota.bin + $PYTHON3 ota_client.py sign $build_dir/firmware-ota.bin popd mv $build_dir/firmware-ota.bin.ota $dest_dir/$descr$fw_tag.ota mv $build_dir/firmware.elf $dest_dir/$descr$fw_tag.elf mv $build_dir/firmware.map $dest_dir/$descr$fw_tag.map - #rm -rf $build_dir + rm -rf $build_dir } # check/get parameters @@ -63,4 +58,4 @@ fi do_build esp8266 GENERIC do_build esp8266-512k GENERIC_512K do_build esp8266-1m GENERIC_1M -do_build_ota esp8266-ota GENERIC ota +do_build_ota esp8266-ota GENERIC_1M ota diff --git a/tools/autobuild/build-mimxrt-latest.sh b/tools/autobuild/build-mimxrt-latest.sh deleted file mode 100755 index 4db65c091..000000000 --- a/tools/autobuild/build-mimxrt-latest.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -# function for building firmware -function do_build() { - descr=$1 - board=$2 - ext=$3 - shift - shift - shift - echo "building $descr $board" - build_dir=/tmp/mimxrt-build-$board - $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1 - mv $build_dir/firmware.$ext $dest_dir/$descr$fw_tag.$ext - rm -rf $build_dir -} - -# check/get parameters -if [ $# != 2 ]; then - echo "usage: $0 " - exit 1 -fi - -fw_tag=$1 -dest_dir=$2 - -# check we are in the correct directory -if [ ! -r modmimxrt.c ]; then - echo "must be in mimxrt directory" - exit 1 -fi - -# build the boards -do_build TEENSY40 TEENSY40 hex -do_build TEENSY41 TEENSY41 hex -do_build MIMXRT1020_EVK MIMXRT1020_EVK bin -do_build MIMXRT1050_EVKB MIMXRT1050_EVKB bin diff --git a/tools/autobuild/build-rp2-latest.sh b/tools/autobuild/build-rp2-latest.sh deleted file mode 100755 index 5124686e2..000000000 --- a/tools/autobuild/build-rp2-latest.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# function for building firmware -function do_build() { - descr=$1 - board=$2 - shift - shift - echo "building $descr $board" - build_dir=/tmp/rp2-build-$board - $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1 - mv $build_dir/firmware.uf2 $dest_dir/$descr$fw_tag.uf2 - rm -rf $build_dir -} - -# check/get parameters -if [ $# != 2 ]; then - echo "usage: $0 " - exit 1 -fi - -fw_tag=$1 -dest_dir=$2 - -# check we are in the correct directory -if [ ! -r modrp2.c ]; then - echo "must be in rp2 directory" - exit 1 -fi - -# build the boards -do_build rp2-pico PICO diff --git a/tools/autobuild/build-stm32-latest.sh b/tools/autobuild/build-stm32-extra.sh similarity index 82% rename from tools/autobuild/build-stm32-latest.sh rename to tools/autobuild/build-stm32-extra.sh index 283c8a45b..43842d6c9 100755 --- a/tools/autobuild/build-stm32-latest.sh +++ b/tools/autobuild/build-stm32-extra.sh @@ -1,4 +1,5 @@ #!/bin/bash +# Build additional variants of pyboard firmware (base variants are built by build-boards.sh). # function for building firmware function do_build() { @@ -10,6 +11,7 @@ function do_build() { build_dir=/tmp/stm-build-$board $MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1 mv $build_dir/firmware.dfu $dest_dir/$descr$fw_tag.dfu + mv $build_dir/firmware.hex $dest_dir/$descr$fw_tag.hex rm -rf $build_dir } @@ -31,26 +33,15 @@ fi # build the versions do_build pybv3 PYBV3 do_build pybv3-network PYBV3 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 -do_build pybv10 PYBV10 do_build pybv10-dp PYBV10 MICROPY_FLOAT_IMPL=double do_build pybv10-thread PYBV10 CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' do_build pybv10-dp-thread PYBV10 MICROPY_FLOAT_IMPL=double CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' do_build pybv10-network PYBV10 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 -do_build pybv11 PYBV11 do_build pybv11-dp PYBV11 MICROPY_FLOAT_IMPL=double do_build pybv11-thread PYBV11 CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' do_build pybv11-dp-thread PYBV11 MICROPY_FLOAT_IMPL=double CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' do_build pybv11-network PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 -do_build pyblitev10 PYBLITEV10 do_build pyblitev10-dp PYBLITEV10 MICROPY_FLOAT_IMPL=double do_build pyblitev10-thread PYBLITEV10 CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' do_build pyblitev10-dp-thread PYBLITEV10 MICROPY_FLOAT_IMPL=double CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' do_build pyblitev10-network PYBLITEV10 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 -do_build PYBD-SF2 PYBD_SF2 -do_build PYBD-SF3 PYBD_SF3 -do_build PYBD-SF6 PYBD_SF6 - -for board in boards/{NUCLEO_*,STM32F*DISC,B_L*,USBDONGLE_WB55,ESPRUINO_PICO} ; do - bd=$(basename $board) - do_build $bd $bd USE_MBOOT=0 MBOOT_ENABLE_PACKING=0 -done diff --git a/tools/ci.sh b/tools/ci.sh index ac2e0b77d..0911e52a6 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -106,16 +106,15 @@ function ci_esp32_idf402_setup { ci_esp32_setup_helper v4.0.2 } -function ci_esp32_idf43_setup { - ci_esp32_setup_helper v4.3 +function ci_esp32_idf44_setup { + # This commit is just before v5.0-dev + ci_esp32_setup_helper 142bb32c50fa9875b8b69fa539a2d59559460d72 } function ci_esp32_build { source esp-idf/export.sh make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/esp32 submodules - make ${MAKEOPTS} -C ports/esp32 - make ${MAKEOPTS} -C ports/esp32 clean make ${MAKEOPTS} -C ports/esp32 USER_C_MODULES=../../../examples/usercmodule/micropython.cmake FROZEN_MANIFEST=$(pwd)/ports/esp32/boards/manifest.py # if [ -d $IDF_PATH/components/esp32c3 ]; then # make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_C3 @@ -123,6 +122,9 @@ function ci_esp32_build { # if [ -d $IDF_PATH/components/esp32s2 ]; then # make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_S2 # fi + # if [ -d $IDF_PATH/components/esp32s3 ]; then + # make ${MAKEOPTS} -C ports/esp32 BOARD=GENERIC_S3 + # fi } ######################################################################################## @@ -281,12 +283,16 @@ function ci_stm32_nucleo_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 submodules git submodule update --init lib/mynewt-nimble + + # Test building various MCU families, some with additional options. make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L073RZ make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L476RG DEBUG=1 - make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_WB55 - make ${MAKEOPTS} -C ports/stm32/mboot BOARD=NUCLEO_WB55 + + # Test building a board with mboot packing enabled (encryption, signing, compression). + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_WB55 USE_MBOOT=1 MBOOT_ENABLE_PACKING=1 + make ${MAKEOPTS} -C ports/stm32/mboot BOARD=NUCLEO_WB55 USE_MBOOT=1 MBOOT_ENABLE_PACKING=1 # Test mboot_pack_dfu.py created a valid file, and that its unpack-dfu command works. BOARD_WB55=ports/stm32/boards/NUCLEO_WB55 BUILD_WB55=ports/stm32/build-NUCLEO_WB55 @@ -598,29 +604,32 @@ function ci_windows_build { ######################################################################################## # ports/zephyr +ZEPHYR_DOCKER_VERSION=v0.21.0 +ZEPHYR_SDK_VERSION=0.13.2 +ZEPHYR_VERSION=v2.7.0 + function ci_zephyr_setup { - docker pull zephyrprojectrtos/ci:v0.17.3 + docker pull zephyrprojectrtos/ci:${ZEPHYR_DOCKER_VERSION} docker run --name zephyr-ci -d -it \ -v "$(pwd)":/micropython \ - -e ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-0.12.4 \ + -e ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-${ZEPHYR_SDK_VERSION} \ -e ZEPHYR_TOOLCHAIN_VARIANT=zephyr \ -e ZEPHYR_BASE=/zephyrproject/zephyr \ -w /micropython/ports/zephyr \ - zephyrprojectrtos/ci:v0.17.3 + zephyrprojectrtos/ci:${ZEPHYR_DOCKER_VERSION} docker ps -a } function ci_zephyr_install { - docker exec zephyr-ci west init --mr v2.6.0 /zephyrproject + docker exec zephyr-ci west init --mr ${ZEPHYR_VERSION} /zephyrproject docker exec -w /zephyrproject zephyr-ci west update docker exec -w /zephyrproject zephyr-ci west zephyr-export } function ci_zephyr_build { docker exec zephyr-ci west build -p auto -b qemu_x86 -- -DCONF_FILE=prj_minimal.conf - docker exec zephyr-ci west build -p auto -b frdm_k64f -- -DCONF_FILE=prj_minimal.conf docker exec zephyr-ci west build -p auto -b qemu_x86 docker exec zephyr-ci west build -p auto -b frdm_k64f docker exec zephyr-ci west build -p auto -b mimxrt1050_evk - docker exec zephyr-ci west build -p auto -b reel_board + docker exec zephyr-ci west build -p auto -b nucleo_wb55rg # for bluetooth } diff --git a/tools/codeformat.py b/tools/codeformat.py index a5d64739a..04cce1d83 100755 --- a/tools/codeformat.py +++ b/tools/codeformat.py @@ -35,6 +35,7 @@ import subprocess # Relative to top-level repo dir. PATHS = [ # C + "drivers/ninaw10/*.[ch]", "extmod/*.[ch]", "extmod/btstack/*.[ch]", "extmod/nimble/*.[ch]", @@ -52,6 +53,7 @@ PATHS = [ "examples/**/*.py", "extmod/**/*.py", "ports/**/*.py", + "ports/mimxrt/**/*.[ch]", "py/**/*.py", "tools/**/*.py", "tests/**/*.py", diff --git a/tools/dfu.py b/tools/dfu.py index 6591436e9..39d68f3b6 100755 --- a/tools/dfu.py +++ b/tools/dfu.py @@ -20,7 +20,7 @@ def consume(fmt, data, names): def cstring(string): - return string.split("\0", 1)[0] + return string.split(b"\0", 1)[0] def compute_crc(data): diff --git a/tools/make-frozen.py b/tools/make-frozen.py deleted file mode 100755 index bc35d3834..000000000 --- a/tools/make-frozen.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# -# Create frozen modules structure for MicroPython. -# -# Usage: -# -# Have a directory with modules to be frozen (only modules, not packages -# supported so far): -# -# frozen/foo.py -# frozen/bar.py -# -# Run script, passing path to the directory above: -# -# ./make-frozen.py frozen > frozen.c -# -# Include frozen.c in your build, having defined MICROPY_MODULE_FROZEN_STR in -# config. -# -from __future__ import print_function -import sys -import os - - -def module_name(f): - return f - - -modules = [] - -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)) - -print("#include ") -print("const char mp_frozen_str_names[] = {") -for f, st in modules: - m = module_name(f) - print('"%s\\0"' % m) -print('"\\0"};') - -print("const uint32_t mp_frozen_str_sizes[] = {") - -for f, st in modules: - print("%d," % st.st_size) - -print("0};") - -print("const char mp_frozen_str_content[] = {") -for f, st in modules: - data = open(sys.argv[1] + "/" + f, "rb").read() - - # We need to properly escape the script data to create a C string. - # When C parses hex characters of the form \x00 it keeps parsing the hex - # data until it encounters a non-hex character. Thus one must create - # strings of the form "data\x01" "abc" to properly encode this kind of - # data. We could just encode all characters as hex digits but it's nice - # to be able to read the resulting C code as ASCII when possible. - - data = bytearray(data) # so Python2 extracts each byte as an integer - esc_dict = {ord("\n"): "\\n", ord("\r"): "\\r", ord('"'): '\\"', ord("\\"): "\\\\"} - chrs = ['"'] - break_str = False - for c in data: - try: - chrs.append(esc_dict[c]) - except KeyError: - if 32 <= c <= 126: - if break_str: - chrs.append('" "') - break_str = False - chrs.append(chr(c)) - else: - chrs.append("\\x%02x" % c) - break_str = True - chrs.append('\\0"') - print("".join(chrs)) - -print('"\\0"};') diff --git a/tools/makemanifest.py b/tools/makemanifest.py index 72fad75a5..c3df17755 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -201,8 +201,6 @@ def freeze_internal(kind, path, script, opt): if not os.path.isdir(path): raise FreezeError("freeze path must be a directory: {}".format(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 or isinstance(script, str) and script.find(".") == -1: # Recursively search `path` for files to freeze, optionally restricted @@ -235,6 +233,73 @@ def freeze_internal(kind, path, script, opt): manifest_list.append((kind, path, script, opt)) +# Formerly make-frozen.py. +# This generates: +# - MP_FROZEN_STR_NAMES macro +# - mp_frozen_str_sizes +# - mp_frozen_str_content +def generate_frozen_str_content(paths): + def module_name(f): + return f + + modules = [] + output = [b"#include \n"] + + for path in paths: + root = path.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((path, fullpath[root_len + 1 :], st)) + + output.append(b"#define MP_FROZEN_STR_NAMES \\\n") + for _path, f, st in modules: + m = module_name(f) + output.append(b'"%s\\0" \\\n' % m.encode()) + output.append(b"\n") + + output.append(b"const uint32_t mp_frozen_str_sizes[] = { ") + + for _path, f, st in modules: + output.append(b"%d, " % st.st_size) + output.append(b"0 };\n") + + output.append(b"const char mp_frozen_str_content[] = {\n") + for path, f, st in modules: + data = open(path + "/" + f, "rb").read() + + # We need to properly escape the script data to create a C string. + # When C parses hex characters of the form \x00 it keeps parsing the hex + # data until it encounters a non-hex character. Thus one must create + # strings of the form "data\x01" "abc" to properly encode this kind of + # data. We could just encode all characters as hex digits but it's nice + # to be able to read the resulting C code as ASCII when possible. + + data = bytearray(data) # so Python2 extracts each byte as an integer + esc_dict = {ord("\n"): b"\\n", ord("\r"): b"\\r", ord('"'): b'\\"', ord("\\"): b"\\\\"} + output.append(b'"') + break_str = False + for c in data: + try: + output.append(esc_dict[c]) + except KeyError: + if 32 <= c <= 126: + if break_str: + output.append(b'" "') + break_str = False + output.append(chr(c).encode()) + else: + output.append(b"\\x%02x" % c) + break_str = True + output.append(b'\\0"\n') + + output.append(b'"\\0"\n};\n\n') + return b"".join(output) + + def main(): # Parse arguments import argparse @@ -264,7 +329,6 @@ def main(): sys.exit(1) # Get paths to tools - MAKE_FROZEN = VARS["MPY_DIR"] + "/tools/make-frozen.py" MPY_CROSS = VARS["MPY_DIR"] + "/mpy-cross/mpy-cross" if sys.platform == "win32": MPY_CROSS += ".exe" @@ -327,10 +391,7 @@ def main(): return # Freeze paths as strings - 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) + output_str = generate_frozen_str_content(str_paths) # Freeze .mpy files if mpy_files: @@ -347,7 +408,7 @@ def main(): ) if res != 0: print("error freezing mpy {}:".format(mpy_files)) - print(str(output_mpy, "utf8")) + print(output_mpy.decode()) sys.exit(1) else: output_mpy = ( @@ -356,8 +417,8 @@ def main(): b"const qstr_pool_t mp_qstr_frozen_const_pool = {\n" b" (qstr_pool_t*)&mp_qstr_const_pool, MP_QSTRnumber_of, 0, false, 0\n" b"};\n" - b'const char mp_frozen_mpy_names[1] = {"\\0"};\n' - b"const mp_raw_code_t *const mp_frozen_mpy_content[1] = {NULL};\n" + b'const char mp_frozen_names[] = { MP_FROZEN_STR_NAMES "\\0"};\n' + b"const mp_raw_code_t *const mp_frozen_mpy_content[] = {NULL};\n" ) # Generate output diff --git a/tools/mpremote/README.md b/tools/mpremote/README.md index a6aaa1755..c294b2081 100644 --- a/tools/mpremote/README.md +++ b/tools/mpremote/README.md @@ -27,6 +27,7 @@ The full list of supported commands are: --capture --inject-code --inject-file + mpremote help -- print list of commands and exit Multiple commands can be specified and they will be run sequentially. Connection and disconnection will be done automatically at the start and end of the execution @@ -50,7 +51,10 @@ Any user configuration, including user-defined shortcuts, can be placed in commands = { "c33": "connect id:334D335C3138", "bl": "bootloader", - "double x=4": "eval x*2", + "double x=4": { + "command": "eval x*2", + "help": "multiply by two" + } } Examples: diff --git a/tools/mpremote/mpremote/main.py b/tools/mpremote/mpremote/main.py index 6e2df5179..99e7bcd9b 100644 --- a/tools/mpremote/mpremote/main.py +++ b/tools/mpremote/mpremote/main.py @@ -18,6 +18,9 @@ MicroPython device over a serial connection. Commands supported are: """ import os, sys +from collections.abc import Mapping +from textwrap import dedent + import serial.tools.list_ports from . import pyboardextended as pyboard @@ -25,21 +28,42 @@ from .console import Console, ConsolePosix _PROG = "mpremote" +_COMMANDS = { + "connect": ( + False, + False, + 1, + """\ + connect to given device + device may be: list, auto, id:x, port:x + or any valid device name/path""", + ), + "disconnect": (False, False, 0, "disconnect current device"), + "mount": (True, False, 1, "mount local directory on device"), + "repl": ( + False, + True, + 0, + """\ + enter REPL + options: + --capture + --inject-code + --inject-file """, + ), + "eval": (True, True, 1, "evaluate and print the string"), + "exec": (True, True, 1, "execute the string"), + "run": (True, True, 1, "run the given local script"), + "fs": (True, True, 1, "execute filesystem commands on the device"), + "help": (False, False, 0, "print help and exit"), +} + _BUILTIN_COMMAND_EXPANSIONS = { # Device connection shortcuts. - "devs": "connect list", - "a0": "connect /dev/ttyACM0", - "a1": "connect /dev/ttyACM1", - "a2": "connect /dev/ttyACM2", - "a3": "connect /dev/ttyACM3", - "u0": "connect /dev/ttyUSB0", - "u1": "connect /dev/ttyUSB1", - "u2": "connect /dev/ttyUSB2", - "u3": "connect /dev/ttyUSB3", - "c0": "connect COM0", - "c1": "connect COM1", - "c2": "connect COM2", - "c3": "connect COM3", + "devs": { + "command": "connect list", + "help": "list available serial ports", + }, # Filesystem shortcuts. "cat": "fs cat", "ls": "fs ls", @@ -52,22 +76,35 @@ _BUILTIN_COMMAND_EXPANSIONS = { "import uos\nprint('mount \\tsize \\tused \\tavail \\tuse%')\nfor _m in [''] + uos.listdir('/'):\n _s = uos.stat('/' + _m)\n if not _s[0] & 1 << 14: continue\n _s = uos.statvfs(_m)\n if _s[0]:\n _size = _s[0] * _s[2]; _free = _s[0] * _s[3]; print(_m, _size, _size - _free, _free, int(100 * (_size - _free) / _size), sep='\\t')", ], # Other shortcuts. - "reset t_ms=100": [ - "exec", - "--no-follow", - "import utime, umachine; utime.sleep_ms(t_ms); umachine.reset()", - ], - "bootloader t_ms=100": [ - "exec", - "--no-follow", - "import utime, umachine; utime.sleep_ms(t_ms); umachine.bootloader()", - ], + "reset t_ms=100": { + "command": [ + "exec", + "--no-follow", + "import utime, umachine; utime.sleep_ms(t_ms); umachine.reset()", + ], + "help": "reset the device after delay", + }, + "bootloader t_ms=100": { + "command": [ + "exec", + "--no-follow", + "import utime, umachine; utime.sleep_ms(t_ms); umachine.bootloader()", + ], + "help": "make the device enter its bootloader", + }, "setrtc": [ "exec", "import machine; machine.RTC().datetime((2020, 1, 1, 0, 10, 0, 0, 0))", ], } +for port_num in range(4): + for prefix, port in [("a", "/dev/ttyACM"), ("u", "/dev/ttyUSB"), ("c", "COM")]: + _BUILTIN_COMMAND_EXPANSIONS["{}{}".format(prefix, port_num)] = { + "command": "connect {}{}".format(port, port_num), + "help": 'connect to serial port "{}{}"'.format(port, port_num), + } + def load_user_config(): # Create empty config object. @@ -111,9 +148,14 @@ def prepare_command_expansions(config): args = () else: args = tuple(c.split("=") for c in cmd[1:]) + + help_message = "" + if isinstance(sub, Mapping): + help_message = sub.get("help", "") + sub = sub["command"] if isinstance(sub, str): sub = sub.split() - _command_expansions[cmd[0]] = (args, sub) + _command_expansions[cmd[0]] = (args, sub, help_message) def do_command_expansion(args): @@ -126,7 +168,7 @@ def do_command_expansion(args): pre = [] while args and args[0] in _command_expansions: cmd = args.pop(0) - exp_args, exp_sub = _command_expansions[cmd] + exp_args, exp_sub, _ = _command_expansions[cmd] for exp_arg in exp_args: exp_arg_name = exp_arg[0] if args and "=" not in args[0]: @@ -365,6 +407,26 @@ def execbuffer(pyb, buf, follow): return ret_val +def print_help(): + def print_commands_help(cmds, help_idx): + max_command_len = max(len(cmd) for cmd in cmds.keys()) + for cmd in sorted(cmds.keys()): + help_message_lines = dedent(cmds[cmd][help_idx]).split("\n") + help_message = help_message_lines[0] + for line in help_message_lines[1:]: + help_message = "{}\n{}{}".format(help_message, " " * (max_command_len + 4), line) + print(" ", cmd, " " * (max_command_len - len(cmd) + 2), help_message, sep="") + + print(_PROG, "-- MicroPython remote control") + print("See https://docs.micropython.org/en/latest/reference/mpremote.html") + + print("\nList of commands:") + print_commands_help(_COMMANDS, 3) + + print("\nList of shortcuts:") + print_commands_help(_command_expansions, 2) + + def main(): config = load_user_config() prepare_command_expansions(config) @@ -376,20 +438,9 @@ def main(): try: while args: do_command_expansion(args) - - cmds = { - "connect": (False, False, 1), - "disconnect": (False, False, 0), - "mount": (True, False, 1), - "repl": (False, True, 0), - "eval": (True, True, 1), - "exec": (True, True, 1), - "run": (True, True, 1), - "fs": (True, True, 1), - } cmd = args.pop(0) try: - need_raw_repl, is_action, num_args_min = cmds[cmd] + need_raw_repl, is_action, num_args_min, _ = _COMMANDS[cmd] except KeyError: print(f"{_PROG}: '{cmd}' is not a command") return 1 @@ -405,6 +456,9 @@ def main(): if pyb is None: did_action = True continue + elif cmd == "help": + print_help() + sys.exit(0) if pyb is None: pyb = do_connect(["auto"]) diff --git a/tools/mpremote/mpremote/pyboardextended.py b/tools/mpremote/mpremote/pyboardextended.py index ccd3098e3..41f360e5f 100644 --- a/tools/mpremote/mpremote/pyboardextended.py +++ b/tools/mpremote/mpremote/pyboardextended.py @@ -21,6 +21,8 @@ fs_hook_cmds = { "CMD_SEEK": 8, "CMD_REMOVE": 9, "CMD_RENAME": 10, + "CMD_MKDIR": 11, + "CMD_RMDIR": 12, } fs_hook_code = """\ @@ -142,7 +144,13 @@ class RemoteFile(uio.IOBase): self.close() def ioctl(self, request, arg): - if request == 4: # CLOSE + if request == 1: # FLUSH + self.flush() + elif request == 2: # SEEK + # This assumes a 32-bit bare-metal machine. + import machine + machine.mem32[arg] = self.seek(machine.mem32[arg], machine.mem32[arg + 4]) + elif request == 4: # CLOSE self.close() return 0 @@ -259,6 +267,24 @@ class RemoteFS: if res < 0: raise OSError(-res) + def mkdir(self, path): + c = self.cmd + c.begin(CMD_MKDIR) + c.wr_str(self.path + path) + res = c.rd_s32() + c.end() + if res < 0: + raise OSError(-res) + + def rmdir(self, path): + c = self.cmd + c.begin(CMD_RMDIR) + c.wr_str(self.path + path) + res = c.rd_s32() + c.end() + if res < 0: + raise OSError(-res) + def stat(self, path): c = self.cmd c.begin(CMD_STAT) @@ -495,6 +521,28 @@ class PyboardCommand: ret = -abs(er.errno) self.wr_s32(ret) + def do_mkdir(self): + path = self.root + self.rd_str() + # self.log_cmd(f"mkdir {path}") + try: + self.path_check(path) + os.mkdir(path) + ret = 0 + except OSError as er: + ret = -abs(er.errno) + self.wr_s32(ret) + + def do_rmdir(self): + path = self.root + self.rd_str() + # self.log_cmd(f"rmdir {path}") + try: + self.path_check(path) + os.rmdir(path) + ret = 0 + except OSError as er: + ret = -abs(er.errno) + self.wr_s32(ret) + cmd_table = { fs_hook_cmds["CMD_STAT"]: do_stat, fs_hook_cmds["CMD_ILISTDIR_START"]: do_ilistdir_start, @@ -506,6 +554,8 @@ class PyboardCommand: fs_hook_cmds["CMD_SEEK"]: do_seek, fs_hook_cmds["CMD_REMOVE"]: do_remove, fs_hook_cmds["CMD_RENAME"]: do_rename, + fs_hook_cmds["CMD_MKDIR"]: do_mkdir, + fs_hook_cmds["CMD_RMDIR"]: do_rmdir, } diff --git a/tools/mpremote/setup.cfg b/tools/mpremote/setup.cfg index 261369384..bb2d0da52 100644 --- a/tools/mpremote/setup.cfg +++ b/tools/mpremote/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = mpremote -version = 0.0.6 +version = 0.1.0 author = Damien George author_email = damien@micropython.org description = Tool for interacting remotely with MicroPython diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 6143816f5..b636d783d 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -132,14 +132,6 @@ def mp_opcode_format(bytecode, ip, count_var_uint): ip_start = ip f = (0x000003A4 >> (2 * ((opcode) >> 4))) & 3 if f == MP_BC_FORMAT_QSTR: - if config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE: - if ( - opcode == MP_BC_LOAD_NAME - or opcode == MP_BC_LOAD_GLOBAL - or opcode == MP_BC_LOAD_ATTR - or opcode == MP_BC_STORE_ATTR - ): - ip += 1 ip += 3 else: extra_byte = (opcode & MP_BC_MASK_EXTRA_BYTE) == 0 @@ -440,10 +432,7 @@ class RawCodeBytecode(RawCode): "// 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("STATIC const 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="") @@ -798,7 +787,6 @@ def read_mpy(filename): raise Exception("incompatible .mpy version") 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 mpy_native_arch = feature_byte >> 2 if mpy_native_arch != MP_NATIVE_ARCH_NONE: @@ -836,14 +824,6 @@ def freeze_mpy(base_qstrs, raw_codes): print('#include "py/nativeglue.h"') print() - print( - "#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE != %u" - % config.MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE - ) - print('#error "incompatible MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE"') - print("#endif") - print() - print("#if MICROPY_LONGINT_IMPL != %u" % config.MICROPY_LONGINT_IMPL) print('#error "incompatible MICROPY_LONGINT_IMPL"') print("#endif") @@ -907,7 +887,11 @@ def freeze_mpy(base_qstrs, raw_codes): rc.freeze(rc.source_file.str.replace("/", "_")[:-3] + "_") print() - print("const char mp_frozen_mpy_names[] = {") + print("const char mp_frozen_names[] = {") + print("#ifdef MP_FROZEN_STR_NAMES") + # makemanifest.py might also include some frozen string content. + print("MP_FROZEN_STR_NAMES") + print("#endif") for rc in raw_codes: module_name = rc.source_file.str print('"%s\\0"' % module_name) @@ -941,11 +925,7 @@ def merge_mpy(raw_codes, output_file): 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[2] = config.native_arch << 2 | config.MICROPY_PY_BUILTINS_STR_UNICODE << 1 header[3] = config.mp_small_int_bits header[4] = 32 # qstr_win_size merged_mpy.extend(header) diff --git a/tools/mpy_cross_all.py b/tools/mpy_cross_all.py index d542bde42..4b1edf9d6 100755 --- a/tools/mpy_cross_all.py +++ b/tools/mpy_cross_all.py @@ -6,14 +6,11 @@ import os.path argparser = argparse.ArgumentParser(description="Compile all .py files to .mpy recursively") argparser.add_argument("-o", "--out", help="output directory (default: input dir)") argparser.add_argument("--target", help="select MicroPython target config") -argparser.add_argument( - "-mcache-lookup-bc", action="store_true", help="cache map lookups in the bytecode" -) argparser.add_argument("dir", help="input directory") args = argparser.parse_args() TARGET_OPTS = { - "unix": "-mcache-lookup-bc", + "unix": "", "baremetal": "", } diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index 852249943..6bc1dbac0 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -48,7 +48,6 @@ 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 @@ -118,9 +117,7 @@ class ArchData: ARCH_DATA = { "x86": ArchData( "EM_386", - MP_NATIVE_ARCH_X86 << 2 - | MICROPY_PY_BUILTINS_STR_UNICODE - | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE, + MP_NATIVE_ARCH_X86 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, 2, 4, (R_386_PC32, R_386_GOT32, R_386_GOT32X), @@ -128,9 +125,7 @@ ARCH_DATA = { ), "x64": ArchData( "EM_X86_64", - MP_NATIVE_ARCH_X64 << 2 - | MICROPY_PY_BUILTINS_STR_UNICODE - | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE, + MP_NATIVE_ARCH_X64 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE, 2, 8, (R_X86_64_GOTPCREL, R_X86_64_REX_GOTPCRELX), diff --git a/tools/pydfu.py b/tools/pydfu.py index ea658d300..f2d845a70 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -84,7 +84,6 @@ if "length" in getargspec(usb.util.get_string).args: def get_string(dev, index): return usb.util.get_string(dev, 255, index) - else: # PyUSB 1.0.0.b2 dropped the length argument def get_string(dev, index): diff --git a/tools/upip.py b/tools/upip.py index 728b843c9..9fb872642 100644 --- a/tools/upip.py +++ b/tools/upip.py @@ -192,9 +192,13 @@ def fatal(msg, exc=None): def install_pkg(pkg_spec, install_path): - data = get_pkg_metadata(pkg_spec) + package = pkg_spec.split("==") + data = get_pkg_metadata(package[0]) - latest_ver = data["info"]["version"] + if len(package) == 1: + latest_ver = data["info"]["version"] + else: + latest_ver = package[1] packages = data["releases"][latest_ver] del data gc.collect() @@ -258,6 +262,8 @@ def get_install_path(): if install_path is None: # sys.path[0] is current module's path install_path = sys.path[1] + if install_path == ".frozen": + install_path = sys.path[2] install_path = expandhome(install_path) return install_path @@ -277,11 +283,11 @@ upip - Simple PyPI package manager for MicroPython Usage: micropython -m upip install [-p ] ... | -r import upip; upip.install(package_or_list, []) -If is not given, packages will be installed into sys.path[1] -(can be set from MICROPYPATH environment variable, if current system -supports that).""" +If isn't given, packages will be installed to sys.path[1], or +sys.path[2] if the former is .frozen (path can be set from MICROPYPATH +environment variable if supported).""" ) - print("Current value of sys.path[1]:", sys.path[1]) + print("Default install path:", get_install_path()) print( """\