diff --git a/.gitattributes b/.gitattributes index 91863791e0..eb32a4d0d4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -17,8 +17,6 @@ tests/basics/string_cr_conversion.py -text tests/basics/string_crlf_conversion.py -text ports/stm32/pybcdc.inf_template -text -ports/stm32/usbd_* -text -ports/stm32/usbdev/** -text ports/stm32/usbhost/** -text ports/cc3200/hal/aes.c -text ports/cc3200/hal/aes.h -text diff --git a/.gitmodules b/.gitmodules index d687c6cf3b..388f9b4f66 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,7 @@ url = https://github.com/atgreen/libffi [submodule "lib/lwip"] path = lib/lwip - url = http://git.savannah.gnu.org/r/lwip.git + url = https://git.savannah.gnu.org/r/lwip.git [submodule "lib/berkeley-db-1.xx"] path = lib/berkeley-db-1.xx url = https://github.com/pfalcon/berkeley-db-1.xx diff --git a/.travis.yml b/.travis.yml index 58b40f168b..9a23a9be77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ compiler: git: depth: 1 env: + - MAKEOPTS="-j4" - TRAVIS_BOARD=feather_huzzah - TRAVIS_BOARD=arduino_zero - TRAVIS_BOARD=circuitplayground_express @@ -57,12 +58,17 @@ before_script: - ([[ $TRAVIS_BOARD != "feather52832" && $TRAVIS_BOARD != "pca10056" ]] || sudo ports/nrf/drivers/bluetooth/download_ble_stack.sh) # For huzzah builds - if [[ $TRAVIS_BOARD = "feather_huzzah" ]]; then wget https://github.com/jepler/esp-open-sdk/releases/download/2018-06-10/xtensa-lx106-elf-standalone.tar.gz && tar xavf xtensa-lx106-elf-standalone.tar.gz; PATH=$(readlink -f xtensa-lx106-elf/bin):$PATH; fi - # For coverage testing (upgrade is used to get latest urllib3 version) - ([[ -z "$TRAVIS_TEST" ]] || sudo pip install --upgrade cpp-coveralls) - ([[ $TRAVIS_TEST != "docs" ]] || sudo pip install Sphinx sphinx-rtd-theme recommonmark) - gcc --version - ([[ -z "$TRAVIS_BOARD" ]] || arm-none-eabi-gcc --version) - python3 --version + + - sudo apt-get install realpath + # For coverage testing (a specific urllib3 version is needed for requests and cpp-coveralls to work together) + - sudo pip install -Iv urllib3==1.22 + - sudo pip install cpp-coveralls + script: # Build mpy-cross first because other builds depend on it. @@ -110,9 +116,17 @@ script: - echo -en 'travis_fold:end:build_docs\\r' + # test when input script comes from stdin + - cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc' + # run coveralls coverage analysis (try to, even if some builds/tests failed) #- (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod) + # run tests on stackless build + # - rm -rf ports/unix/build-coverage + # - make ${MAKEOPTS} -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" + # - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) + after_failure: - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) - (grep "FAIL" ports/qemu-arm/build/console.out) diff --git a/docs/library/_thread.rst b/docs/library/_thread.rst new file mode 100644 index 0000000000..47c1c2392d --- /dev/null +++ b/docs/library/_thread.rst @@ -0,0 +1,12 @@ +:mod:`_thread` -- multithreading support +======================================== + +.. module:: _thread + :synopsis: multithreading support + +|see_cpython_module| :mod:`python:_thread`. + +This module implements multithreading support. + +This module is highly experimental and its API is not yet fully settled +and not yet described in this documentation. diff --git a/docs/library/array.rst b/docs/library/array.rst index 0f1310b687..859b370ea8 100644 --- a/docs/library/array.rst +++ b/docs/library/array.rst @@ -16,14 +16,14 @@ Classes .. class:: array.array(typecode, [iterable]) Create array with elements of given type. Initial contents of the - array are given by an `iterable`. If it is not provided, an empty + array are given by *iterable*. If it is not provided, an empty array is created. .. method:: append(val) - Append new element to the end of array, growing it. + Append new element *val* to the end of array, growing it. .. method:: extend(iterable) - Append new elements as contained in an iterable to the end of + Append new elements as contained in *iterable* to the end of array, growing it. diff --git a/docs/library/btree.rst b/docs/library/btree.rst index 303a936ad9..3059da7a47 100644 --- a/docs/library/btree.rst +++ b/docs/library/btree.rst @@ -7,7 +7,7 @@ :synopsis: simple BTree database The ``btree`` module implements a simple key-value database using external -storage (disk files, or in general case, a random-access stream). Keys are +storage (disk files, or in general case, a random-access `stream`). Keys are stored sorted in the database, and besides efficient retrieval by a key value, a database also supports efficient ordered range scans (retrieval of values with the keys in a given range). On the application interface diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 80961b8724..3117525dda 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -150,6 +150,14 @@ Constants Red Green Blue (16-bit, 5+6+5) color format +.. data:: framebuf.GS2_HMSB + + Grayscale (2-bit) color format + .. data:: framebuf.GS4_HMSB Grayscale (4-bit) color format + +.. data:: framebuf.GS8 + + Grayscale (8-bit) color format diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index 59e1886fa2..0ba3fbbc53 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -35,6 +35,18 @@ Functions compilation of scripts, and returns ``None``. Otherwise it returns the current optimisation level. + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + .. function:: alloc_emergency_exception_buf(size) Allocate *size* bytes of RAM for the emergency exception buffer (a good @@ -114,5 +126,14 @@ Functions the heap may be locked) and scheduling a function to call later will lift those restrictions. - There is a finite stack to hold the scheduled functions and `schedule` + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite stack to hold the scheduled functions and `schedule()` will raise a `RuntimeError` if the stack is full. diff --git a/docs/library/sys.rst b/docs/library/sys.rst index bb92850b89..c43218509c 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -105,15 +105,15 @@ Constants .. data:: stderr - Standard error stream. + Standard error `stream`. .. data:: stdin - Standard input stream. + Standard input `stream`. .. data:: stdout - Standard output stream. + Standard output `stream`. .. data:: version diff --git a/docs/library/uctypes.rst b/docs/library/uctypes.rst index 55de9a0a24..f71b00c1e4 100644 --- a/docs/library/uctypes.rst +++ b/docs/library/uctypes.rst @@ -10,7 +10,7 @@ This module implements "foreign data interface" for MicroPython. The idea behind it is similar to CPython's ``ctypes`` modules, but the actual API is different, streamlined and optimized for small size. The basic idea of the module is to define data structure layout with about the same power as the -C language allows, and the access it using familiar dot-syntax to reference +C language allows, and then access it using familiar dot-syntax to reference sub-fields. .. seealso:: @@ -31,25 +31,25 @@ Following are encoding examples for various field types: * Scalar types:: - "field_name": uctypes.UINT32 | 0 + "field_name": offset | uctypes.UINT32 in other words, value is scalar type identifier ORed with field offset (in bytes) from the start of the structure. * Recursive structures:: - "sub": (2, { - "b0": uctypes.UINT8 | 0, - "b1": uctypes.UINT8 | 1, + "sub": (offset, { + "b0": 0 | uctypes.UINT8, + "b1": 1 | uctypes.UINT8, }) i.e. value is a 2-tuple, first element of which is offset, and second is a structure descriptor dictionary (note: offsets in recursive descriptors - are relative to a structure it defines). + are relative to the structure it defines). * Arrays of primitive types:: - "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + "arr": (offset | uctypes.ARRAY, size | uctypes.UINT8), i.e. value is a 2-tuple, first element of which is ARRAY flag ORed with offset, and second is scalar element type ORed number of elements @@ -57,7 +57,7 @@ Following are encoding examples for various field types: * Arrays of aggregate types:: - "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "arr2": (offset | uctypes.ARRAY, size, {"b": 0 | uctypes.UINT8}), i.e. value is a 3-tuple, first element of which is ARRAY flag ORed with offset, second is a number of elements in array, and third is @@ -65,21 +65,21 @@ Following are encoding examples for various field types: * Pointer to a primitive type:: - "ptr": (uctypes.PTR | 0, uctypes.UINT8), + "ptr": (offset | uctypes.PTR, uctypes.UINT8), i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, and second is scalar element type. * Pointer to an aggregate type:: - "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}), + "ptr2": (offset | uctypes.PTR, {"b": 0 | uctypes.UINT8}), i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, second is descriptor of type pointed to. * Bitfields:: - "bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN, + "bitf0": offset | uctypes.BFUINT16 | lsbit << uctypes.BF_POS | bitsize << uctypes.BF_LEN, i.e. value is type of scalar value containing given bitfield (typenames are similar to scalar types, but prefixes with "BF"), ORed with offset for @@ -88,20 +88,21 @@ Following are encoding examples for various field types: BF_POS and BF_LEN positions, respectively. Bitfield position is counted from the least significant bit, and is the number of right-most bit of a field (in other words, it's a number of bits a scalar needs to be shifted - right to extra the bitfield). + right to extract the bitfield). - In the example above, first UINT16 value will be extracted at offset 0 + In the example above, first a UINT16 value will be extracted at offset 0 (this detail may be important when accessing hardware registers, where particular access size and alignment are required), and then bitfield - whose rightmost bit is least-significant bit of this UINT16, and length - is 8 bits, will be extracted - effectively, this will access - least-significant byte of UINT16. + whose rightmost bit is *lsbit* bit of this UINT16, and length + is *bitsize* bits, will be extracted. For example, if *lsbit* is 0 and + *bitsize* is 8, then effectively it will access least-significant byte + of UINT16. Note that bitfield operations are independent of target byte endianness, in particular, example above will access least-significant byte of UINT16 in both little- and big-endian structures. But it depends on the least significant bit being numbered 0. Some targets may use different - numbering in their native ABI, but ``uctypes`` always uses normalized + numbering in their native ABI, but ``uctypes`` always uses the normalized numbering described above. Module contents diff --git a/docs/library/uio.rst b/docs/library/uio.rst index 5ae8b9ecba..d1f7c111fa 100644 --- a/docs/library/uio.rst +++ b/docs/library/uio.rst @@ -8,7 +8,7 @@ |see_cpython_module| :mod:`cpython:io`. -This module contains additional types of stream (file-like) objects +This module contains additional types of ``stream`` (file-like) objects and helper functions. Conceptual hierarchy diff --git a/docs/library/ujson.rst b/docs/library/ujson.rst index 080ee2d036..ef9c70c259 100644 --- a/docs/library/ujson.rst +++ b/docs/library/ujson.rst @@ -14,11 +14,24 @@ data format. Functions --------- +.. function:: dump(obj, stream) + + Serialise *obj* to a JSON string, writing it to the given *stream*. + .. function:: dumps(obj) - Return ``obj`` represented as a JSON string. + Return *obj* represented as a JSON string. + +.. function:: load(stream) + + Parse the given *stream*, interpreting it as a JSON string and + deserialising the data to a Python object. The resulting object is + returned. + + Parsing continues until end-of-file is encountered. + A :exc:`ValueError` is raised if the data in *stream* is not correctly formed. .. function:: loads(str) - Parse the JSON ``str`` and return an object. Raises ValueError if the + Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the string is not correctly formed. diff --git a/docs/library/ure.rst b/docs/library/ure.rst index c6457de9a8..2447de1210 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -17,8 +17,9 @@ Supported operators are: ``'.'`` Match any character. -``'[]'`` - Match set of characters. Individual characters and ranges are supported. +``'[...]'`` + Match set of characters. Individual characters and ranges are supported, + including negated sets (e.g. ``[^a-c]``). ``'^'`` @@ -38,18 +39,19 @@ Supported operators are: ``'|'`` -``'()'`` +``'(...)'`` Grouping. Each group is capturing (a substring it captures can be accessed with `match.group()` method). -Counted repetitions (``{m,n}``), more advanced assertions, named groups, -etc. are not supported. +**NOT SUPPORTED**: Counted repetitions (``{m,n}``), more advanced assertions +(``\b``, ``\B``), named groups (``(?P...)``), non-capturing groups +(``(?:...)``), etc. Functions --------- -.. function:: compile(regex_str) +.. function:: compile(regex_str, [flags]) Compile regular expression, return `regex ` object. @@ -67,6 +69,7 @@ Functions .. data:: DEBUG Flag value, display debug information about compiled expression. + (Availability depends on `MicroPython port`.) .. _regex: diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index 685f5b318b..fb365facd1 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -9,7 +9,7 @@ |see_cpython_module| :mod:`cpython:select`. This module provides functions to efficiently wait for events on multiple -streams (select streams which are ready for operations). +`streams ` (select streams which are ready for operations). Functions --------- @@ -35,14 +35,17 @@ Methods .. method:: poll.register(obj[, eventmask]) - Register *obj* for polling. *eventmask* is logical OR of: + Register `stream` *obj* for polling. *eventmask* is logical OR of: - * ``select.POLLIN`` - data available for reading - * ``select.POLLOUT`` - more data can be written - * ``select.POLLERR`` - error occurred - * ``select.POLLHUP`` - end of stream/connection termination detected + * ``uselect.POLLIN`` - data available for reading + * ``uselect.POLLOUT`` - more data can be written - *eventmask* defaults to ``select.POLLIN | select.POLLOUT``. + Note that flags like ``uselect.POLLHUP`` and ``uselect.POLLERR`` are + *not* valid as input eventmask (these are unsolicited events which + will be returned from `poll()` regardless of whether they are asked + for). This semantics is per POSIX. + + *eventmask* defaults to ``uselect.POLLIN | uselect.POLLOUT``. .. method:: poll.unregister(obj) @@ -52,16 +55,23 @@ Methods Modify the *eventmask* for *obj*. -.. method:: poll.poll([timeout]) +.. method:: poll.poll(timeout=-1) - Wait for at least one of the registered objects to become ready. Returns - list of (``obj``, ``event``, ...) tuples, ``event`` element specifies - which events happened with a stream and is a combination of ``select.POLL*`` - constants described above. There may be other elements in tuple, depending - on a platform and version, so don't assume that its size is 2. In case of - timeout, an empty list is returned. + Wait for at least one of the registered objects to become ready or have an + exceptional condition, with optional timeout in milliseconds (if *timeout* + arg is not specified or -1, there is no timeout). - Timeout is in milliseconds. + Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in + tuple, depending on a platform and version, so don't assume that its size is 2. + The ``event`` element specifies which events happened with a stream and + is a combination of ``uselect.POLL*`` constants described above. Note that + flags ``uselect.POLLHUP`` and ``uselect.POLLERR`` can be returned at any time + (even if were not asked for), and must be acted on accordingly (the + corresponding stream unregistered from poll and likely closed), because + otherwise all further invocations of `poll()` may return immediately with + these flags set for this stream again. + + In case of timeout, an empty list is returned. .. admonition:: Difference to CPython :class: attention @@ -70,15 +80,15 @@ Methods .. method:: poll.ipoll(timeout=-1, flags=0) - Like :meth:`poll.poll`, but instead returns an iterator which yields + Like :meth:`poll.poll`, but instead returns an iterator which yields a ``callee-owned tuples``. This function provides efficient, allocation-free way to poll on streams. If *flags* is 1, one-shot behavior for events is employed: streams for - which events happened, event mask will be automatically reset (equivalent - to ``poll.modify(obj, 0)``), so new events for such a stream won't be - processed until new mask is set with `poll.modify()`. This behavior is - useful for asynchronous I/O schedulers. + which events happened will have their event masks automatically reset + (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream + won't be processed until new mask is set with `poll.modify()`. This + behavior is useful for asynchronous I/O schedulers. .. admonition:: Difference to CPython :class: attention diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst index b07ba44130..582742f2e3 100644 --- a/docs/library/usocket.rst +++ b/docs/library/usocket.rst @@ -14,7 +14,7 @@ This module provides access to the BSD socket interface. .. admonition:: Difference to CPython :class: attention - For efficiency and consistency, socket objects in MicroPython implement a stream + For efficiency and consistency, socket objects in MicroPython implement a `stream` (file-like) interface directly. In CPython, you need to convert a socket to a file-like object using `makefile()` method. This method is still supported by MicroPython (but is a no-op), so where compatibility with CPython matters, @@ -245,7 +245,7 @@ Methods Not every ``MicroPython port`` supports this method. A more portable and generic solution is to use `uselect.poll` object. This allows to wait on multiple objects at the same time (and not just on sockets, but on generic - stream objects which support polling). Example:: + `stream` objects which support polling). Example:: # Instead of: s.settimeout(1.0) # time in seconds diff --git a/docs/library/ussl.rst b/docs/library/ussl.rst index 34db3151d6..5df2e5b537 100644 --- a/docs/library/ussl.rst +++ b/docs/library/ussl.rst @@ -17,13 +17,13 @@ Functions .. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None) - Takes a stream *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), + Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), and returns an instance of ssl.SSLSocket, which wraps the underlying stream in - an SSL context. Returned object has the usual stream interface methods like + an SSL context. Returned object has the usual `stream` interface methods like ``read()``, ``write()``, etc. In MicroPython, the returned object does not expose socket interface and methods like ``recv()``, ``send()``. In particular, a server-side SSL socket should be created from a normal socket returned from - `accept()` on a non-SSL listening server socket. + :meth:`~usocket.socket.accept()` on a non-SSL listening server socket. Depending on the underlying module implementation in a particular ``MicroPython port``, some or all keyword arguments above may be not supported. diff --git a/docs/library/uzlib.rst b/docs/library/uzlib.rst index 2a2d9668c4..f736ace81d 100644 --- a/docs/library/uzlib.rst +++ b/docs/library/uzlib.rst @@ -27,7 +27,7 @@ Functions .. class:: DecompIO(stream, wbits=0) - Create a stream wrapper which allows transparent decompression of + Create a `stream` wrapper which allows transparent decompression of compressed data in another *stream*. This allows to process compressed streams with data larger than available heap size. In addition to values described in :func:`decompress`, *wbits* may take values diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst new file mode 100644 index 0000000000..8be2461c2d --- /dev/null +++ b/docs/reference/packages.rst @@ -0,0 +1,312 @@ +Distribution packages, package management, and deploying applications +===================================================================== + +Just as the "big" Python, MicroPython supports creation of "third party" +packages, distributing them, and easily installing them in each user's +environment. This chapter discusses how these actions are achieved. +Some familiarity with Python packaging is recommended. + +Overview +-------- + +Steps below represent a high-level workflow when creating and consuming +packages: + +1. Python modules and packages are turned into distribution package + archives, and published at the Python Package Index (PyPI). +2. `upip` package manager can be used to install a distribution package + on a `MicroPython port` with networking capabilities (for example, + on the Unix port). +3. For ports without networking capabilities, an "installation image" + can be prepared on the Unix port, and transferred to a device by + suitable means. +4. For low-memory ports, the installation image can be frozen as the + bytecode into MicroPython executable, thus minimizing the memory + storage overheads. + +The sections below describe this process in details. + +Distribution packages +--------------------- + +Python modules and packages can be packaged into archives suitable for +transfer between systems, storing at the well-known location (PyPI), +and downloading on demand for deployment. These archives are known as +*distribution packages* (to differentiate them from Python packages +(means to organize Python source code)). + +The MicroPython distribution package format is a well-known tar.gz +format, with some adaptations however. The Gzip compressor, used as +an external wrapper for TAR archives, by default uses 32KB dictionary +size, which means that to uncompress a compressed stream, 32KB of +contguous memory needs to be allocated. This requirement may be not +satisfiable on low-memory devices, which may have total memory available +less than that amount, and even if not, a contiguous block like that +may be hard to allocate due to memory fragmentation. To accommodate +these constraints, MicroPython distribution packages use Gzip compression +with the dictionary size of 4K, which should be a suitable compromise +with still achieving some compression while being able to uncompressed +even by the smallest devices. + +Besides the small compression dictionary size, MicroPython distribution +packages also have other optimizations, like removing any files from +the archive which aren't used by the installation process. In particular, +`upip` package manager doesn't execute ``setup.py`` during installation +(see below), and thus that file is not included in the archive. + +At the same time, these optimizations make MicroPython distribution +packages not compatible with `CPython`'s package manager, ``pip``. +This isn't considered a big problem, because: + +1. Packages can be installed with `upip`, and then can be used with + CPython (if they are compatible with it). +2. In the other direction, majority of CPython packages would be + incompatible with MicroPython by various reasons, first of all, + the reliance on features not implemented by MicroPython. + +Summing up, the MicroPython distribution package archives are highly +optimized for MicroPython's target environments, which are highly +resource constrained devices. + + +``upip`` package manager +------------------------ + +MicroPython distribution packages are intended to be installed using +the `upip` package manager. `upip` is a Python application which is +usually distributed (as frozen bytecode) with network-enabled +`MicroPython ports `. At the very least, +`upip` is available in the `MicroPython Unix port`. + +On any `MicroPython port` providing `upip`, it can be accessed as +following:: + + import upip + upip.help() + upip.install(package_or_package_list, [path]) + +Where *package_or_package_list* is the name of a distribution +package to install, or a list of such names to install multiple +packages. Optional *path* parameter specifies filesystem +location to install under and defaults to the standard library +location (see below). + +An example of installing a specific package and then using it:: + + >>> import upip + >>> upip.install("micropython-pystone_lowmem") + [...] + >>> import pystone_lowmem + >>> pystone_lowmem.main() + +Note that the name of Python package and the name of distribution +package for it in general don't have to match, and oftentimes they +don't. This is because PyPI provides a central package repository +for all different Python implementations and versions, and thus +distribution package names may need to be namespaced for a particular +implementation. For example, all packages from `micropython-lib` +follow this naming convention: for a Python module or package named +``foo``, the distribution package name is ``micropython-foo``. + +For the ports which run MicroPython executable from the OS command +prompts (like the Unix port), `upip` can be (and indeed, usually is) +run from the command line instead of MicroPython's own REPL. The +commands which corresponds to the example above are:: + + micropython -m upip -h + micropython -m upip install [-p ] ... + micropython -m upip install micropython-pystone_lowmem + +[TODO: Describe installation path.] + + +Cross-installing packages +------------------------- + +For `MicroPython ports ` without native networking +capabilities, the recommend process is "cross-installing" them into a +"directory image" using the `MicroPython Unix port`, and then +transferring this image to a device by suitable means. + +Installing to a directory image involves using ``-p`` switch to `upip`:: + + micropython -m upip install -p install_dir micropython-pystone_lowmem + +After this command, the package content (and contents of every depenency +packages) will be available in the ``install_dir/`` subdirectory. You +would need to transfer contents of this directory (without the +``install_dir/`` prefix) to the device, at the suitable location, where +it can be found by the Python ``import`` statement (see discussion of +the `upip` installation path above). + + +Cross-installing packages with freezing +--------------------------------------- + +For the low-memory `MicroPython ports `, the process +described in the previous section does not provide the most efficient +resource usage,because the packages are installed in the source form, +so need to be compiled to the bytecome on each import. This compilation +requires RAM, and the resulting bytecode is also stored in RAM, reducing +its amount available for storing application data. Moreover, the process +above requires presence of the filesystem on a device, and the most +resource-constrained devices may not even have it. + +The bytecode freezing is a process which resolves all the issues +mentioned above: + +* The source code is pre-compiled into bytecode and store as such. +* The bytecode is stored in ROM, not RAM. +* Filesystem is not required for frozen packages. + +Using frozen bytecode requires building the executable (firmware) +for a given `MicroPython port` from the C source code. Consequently, +the process is: + +1. Follow the instructions for a particular port on setting up a + toolchain and building the port. For example, for ESP8266 port, + study instructions in ``ports/esp8266/README.md`` and follow them. + Make sure you can build the port and deploy the resulting + executable/firmware successfully before proceeding to the next steps. +2. Build `MicroPython Unix port` and make sure it is in your PATH and + you can execute ``micropython``. +3. Change to port's directory (e.g. ``ports/esp8266/`` for ESP8266). +4. Run ``make clean-frozen``. This step cleans up any previous + modules which were installed for freezing (consequently, you need + to skip this step to add additional modules, instead of starting + from scratch). +5. Run ``micropython -m upip install -p modules ...`` to + install packages you want to freeze. +6. Run ``make clean``. +7. Run ``make``. + +After this, you should have the executable/firmware with modules as +the bytecode inside, which you can deploy the usual way. + +Few notes: + +1. Step 5 in the sequence above assumes that the distribution package + is available from PyPI. If that is not the case, you would need + to copy Python source files manually to ``modules/`` subdirectory + of the port port directory. (Note that upip does not support + installing from e.g. version control repositories). +2. The firmware for baremetal devices usually has size restrictions, + so adding too many frozen modules may overflow it. Usually, you + would get a linking error if this happens. However, in some cases, + an image may be produced, which is not runnable on a device. Such + cases are in general bugs, and should be reported and further + investigated. If you face such a situation, as an initial step, + you may want to decrease the amount of frozen modules included. + + +Creating distribution packages +------------------------------ + +Distribution packages for MicroPython are created in the same manner +as for CPython or any other Python implementation, see references at +the end of chapter. Setuptools (instead of distutils) should be used, +because distutils do not support dependencies and other features. "Source +distribution" (``sdist``) format is used for packaging. The post-processing +discussed above, (and pre-processing discussed in the following section) +is achieved by using custom ``sdist`` command for setuptools. Thus, packaging +steps remain the same as for the standard setuptools, the user just +needs to override ``sdist`` command implementation by passing the +appropriate argument to ``setup()`` call:: + + from setuptools import setup + import sdist_upip + + setup( + ..., + cmdclass={'sdist': sdist_upip.sdist} + ) + +The sdist_upip.py module as referenced above can be found in +`micropython-lib`: +https://github.com/micropython/micropython-lib/blob/master/sdist_upip.py + + +Application resources +--------------------- + +A complete application, besides the source code, oftentimes also consists +of data files, e.g. web page templates, game images, etc. It's clear how +to deal with those when application is installed manually - you just put +those data files in the filesystem at some location and use the normal +file access functions. + +The situation is different when deploying applications from packages - this +is more advanced, streamlined and flexible way, but also requires more +advanced approach to accessing data files. This approach is treating +the data files as "resources", and abstracting away access to them. + +Python supports resource access using its "setuptools" library, using +``pkg_resources`` module. MicroPython, following its usual approach, +implements subset of the functionality of that module, specifically +``pkg_resources.resource_stream(package, resource)`` function. +The idea is that an application calls this function, passing a +resource identifier, which is a relative path to data file within +the specified package (usually top-level application package). It +returns a stream object which can be used to access resource contents. +Thus, the ``resource_stream()`` emulates interface of the standard +`open()` function. + +Implementation-wise, ``resource_stream()`` uses file operations +underlyingly, if distribution package is install in the filesystem. +However, it also supports functioning without the underlying filesystem, +e.g. if the package is frozen as the bytecode. This however requires +an extra intermediate step when packaging application - creation of +"Python resource module". + +The idea of this module is to convert binary data to a Python bytes +object, and put it into the dictionary, indexed by the resource name. +This conversion is done automatically using overridden ``sdist`` command +described in the previous section. + +Let's trace the complete process using the following example. Suppose +your application has the following structure:: + + my_app/ + __main__.py + utils.py + data/ + page.html + image.png + +``__main__.py`` and ``utils.py`` should access resources using the +following calls:: + + import pkg_resources + + pkg_resources.resource_stream(__name__, "data/page.html") + pkg_resources.resource_stream(__name__, "data/image.png") + +You can develop and debug using the `MicroPython Unix port` as usual. +When time comes to make a distribution package out of it, just use +overridden "sdist" command from sdist_upip.py module as described in +the previous section. + +This will create a Python resource module named ``R.py``, based on the +files declared in ``MANIFEST`` or ``MANIFEST.in`` files (any non-``.py`` +file will be considered a resource and added to ``R.py``) - before +proceeding with the normal packaging steps. + +Prepared like this, your application will work both when deployed to +filesystem and as frozen bytecode. + +If you would like to debug ``R.py`` creation, you can run:: + + python3 setup.py sdist --manifest-only + +Alternatively, you can use tools/mpy_bin2res.py script from the +MicroPython distribution, in which can you will need to pass paths +to all resource files:: + + mpy_bin2res.py data/page.html data/image.png + +References +---------- + +* Python Packaging User Guide: https://packaging.python.org/ +* Setuptools documentation: https://setuptools.readthedocs.io/ +* Distutils documentation: https://docs.python.org/3/library/distutils.html diff --git a/drivers/bus/qspi.h b/drivers/bus/qspi.h new file mode 100644 index 0000000000..31c9d14fca --- /dev/null +++ b/drivers/bus/qspi.h @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H +#define MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H + +#include "py/mphal.h" + +enum { + MP_QSPI_IOCTL_INIT, + MP_QSPI_IOCTL_DEINIT, + MP_QSPI_IOCTL_BUS_ACQUIRE, + MP_QSPI_IOCTL_BUS_RELEASE, +}; + +typedef struct _mp_qspi_proto_t { + int (*ioctl)(void *self, uint32_t cmd); + void (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data); + void (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src); + uint32_t (*read_cmd)(void *self, uint8_t cmd, size_t len); + void (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest); +} mp_qspi_proto_t; + +typedef struct _mp_soft_qspi_obj_t { + mp_hal_pin_obj_t cs; + mp_hal_pin_obj_t clk; + mp_hal_pin_obj_t io0; + mp_hal_pin_obj_t io1; + mp_hal_pin_obj_t io2; + mp_hal_pin_obj_t io3; +} mp_soft_qspi_obj_t; + +extern const mp_qspi_proto_t mp_soft_qspi_proto; + +#endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H diff --git a/drivers/bus/softqspi.c b/drivers/bus/softqspi.c new file mode 100644 index 0000000000..10c5992466 --- /dev/null +++ b/drivers/bus/softqspi.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "drivers/bus/qspi.h" + +#define CS_LOW(self) mp_hal_pin_write(self->cs, 0) +#define CS_HIGH(self) mp_hal_pin_write(self->cs, 1) + +#ifdef MICROPY_HW_SOFTQSPI_SCK_LOW + +// Use externally provided functions for SCK control and IO reading +#define SCK_LOW(self) MICROPY_HW_SOFTQSPI_SCK_LOW(self) +#define SCK_HIGH(self) MICROPY_HW_SOFTQSPI_SCK_HIGH(self) +#define NIBBLE_READ(self) MICROPY_HW_SOFTQSPI_NIBBLE_READ(self) + +#else + +// Use generic pin functions for SCK control and IO reading +#define SCK_LOW(self) mp_hal_pin_write(self->clk, 0) +#define SCK_HIGH(self) mp_hal_pin_write(self->clk, 1) +#define NIBBLE_READ(self) ( \ + mp_hal_pin_read(self->io0) \ + | (mp_hal_pin_read(self->io1) << 1) \ + | (mp_hal_pin_read(self->io2) << 2) \ + | (mp_hal_pin_read(self->io3) << 3)) + +#endif + +STATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) { + mp_hal_pin_write(self->io0, v & 1); + mp_hal_pin_write(self->io1, (v >> 1) & 1); + mp_hal_pin_write(self->io2, (v >> 2) & 1); + mp_hal_pin_write(self->io3, (v >> 3) & 1); +} + +STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + + switch (cmd) { + case MP_QSPI_IOCTL_INIT: + mp_hal_pin_high(self->cs); + mp_hal_pin_output(self->cs); + + // Configure pins + mp_hal_pin_write(self->clk, 0); + mp_hal_pin_output(self->clk); + //mp_hal_pin_write(self->clk, 1); + mp_hal_pin_output(self->io0); + mp_hal_pin_input(self->io1); + mp_hal_pin_write(self->io2, 1); + mp_hal_pin_output(self->io2); + mp_hal_pin_write(self->io3, 1); + mp_hal_pin_output(self->io3); + break; + } + + return 0; // success +} + +STATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) { + // Will run as fast as possible, limited only by CPU speed and GPIO time + mp_hal_pin_input(self->io1); + mp_hal_pin_output(self->io0); + if (self->io3) { + mp_hal_pin_write(self->io2, 1); + mp_hal_pin_output(self->io2); + mp_hal_pin_write(self->io3, 1); + mp_hal_pin_output(self->io3); + } + if (src) { + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->io0, (data_out >> 7) & 1); + mp_hal_pin_write(self->clk, 1); + data_in = (data_in << 1) | mp_hal_pin_read(self->io1); + mp_hal_pin_write(self->clk, 0); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + } else { + for (size_t i = 0; i < len; ++i) { + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j) { + mp_hal_pin_write(self->clk, 1); + data_in = (data_in << 1) | mp_hal_pin_read(self->io1); + mp_hal_pin_write(self->clk, 0); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + } +} + +STATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) { + // Make all IO lines input + mp_hal_pin_input(self->io2); + mp_hal_pin_input(self->io3); + mp_hal_pin_input(self->io0); + mp_hal_pin_input(self->io1); + + // Will run as fast as possible, limited only by CPU speed and GPIO time + while (len--) { + SCK_HIGH(self); + uint8_t data_in = NIBBLE_READ(self); + SCK_LOW(self); + SCK_HIGH(self); + *buf++ = (data_in << 4) | NIBBLE_READ(self); + SCK_LOW(self); + } +} + +STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) { + // Make all IO lines output + mp_hal_pin_output(self->io2); + mp_hal_pin_output(self->io3); + mp_hal_pin_output(self->io0); + mp_hal_pin_output(self->io1); + + // Will run as fast as possible, limited only by CPU speed and GPIO time + for (size_t i = 0; i < len; ++i) { + nibble_write(self, buf[i] >> 4); + SCK_HIGH(self); + SCK_LOW(self); + + nibble_write(self, buf[i]); + SCK_HIGH(self); + SCK_LOW(self); + } + + //mp_hal_pin_input(self->io1); +} + +STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint32_t cmd_buf = cmd | data << 8; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, NULL); + CS_HIGH(self); +} + +STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint8_t cmd_buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + CS_LOW(self); + mp_soft_qspi_transfer(self, 4, cmd_buf, NULL); + mp_soft_qspi_transfer(self, len, src, NULL); + CS_HIGH(self); +} + +STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint32_t cmd_buf = cmd; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf); + CS_HIGH(self); + return cmd_buf >> 8; +} + +STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr}; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1, cmd_buf, NULL); + mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles) + mp_soft_qspi_qread(self, len, dest); + CS_HIGH(self); +} + +const mp_qspi_proto_t mp_soft_qspi_proto = { + .ioctl = mp_soft_qspi_ioctl, + .write_cmd_data = mp_soft_qspi_write_cmd_data, + .write_cmd_addr_data = mp_soft_qspi_write_cmd_addr_data, + .read_cmd = mp_soft_qspi_read_cmd, + .read_cmd_qaddr_qdata = mp_soft_qspi_read_cmd_qaddr_qdata, +}; diff --git a/drivers/bus/softspi.c b/drivers/bus/softspi.c new file mode 100644 index 0000000000..bc12d89d3b --- /dev/null +++ b/drivers/bus/softspi.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "drivers/bus/spi.h" + +int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) { + mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in; + + switch (cmd) { + case MP_SPI_IOCTL_INIT: + mp_hal_pin_write(self->sck, self->polarity); + mp_hal_pin_output(self->sck); + mp_hal_pin_output(self->mosi); + mp_hal_pin_input(self->miso); + break; + + case MP_SPI_IOCTL_DEINIT: + break; + } + + return 0; +} + +void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in; + uint32_t delay_half = self->delay_half; + + // only MSB transfer is implemented + + // If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured + // delay_half is equal to this value, then the software SPI implementation + // will run as fast as possible, limited only by CPU speed and GPIO time. + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) { + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + mp_hal_pin_write(self->sck, 1 - self->polarity); + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + mp_hal_pin_write(self->sck, self->polarity); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + return; + } + #endif + + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, 1 - self->polarity); + } else { + mp_hal_pin_write(self->sck, 1 - self->polarity); + mp_hal_delay_us_fast(delay_half); + } + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, self->polarity); + } else { + mp_hal_pin_write(self->sck, self->polarity); + mp_hal_delay_us_fast(delay_half); + } + } + if (dest != NULL) { + dest[i] = data_in; + } + } +} + +const mp_spi_proto_t mp_soft_spi_proto = { + .ioctl = mp_soft_spi_ioctl, + .transfer = mp_soft_spi_transfer, +}; diff --git a/drivers/bus/spi.h b/drivers/bus/spi.h new file mode 100644 index 0000000000..6d1b9c2f83 --- /dev/null +++ b/drivers/bus/spi.h @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_DRIVERS_BUS_SPI_H +#define MICROPY_INCLUDED_DRIVERS_BUS_SPI_H + +#include "py/mphal.h" + +enum { + MP_SPI_IOCTL_INIT, + MP_SPI_IOCTL_DEINIT, +}; + +typedef struct _mp_spi_proto_t { + int (*ioctl)(void *self, uint32_t cmd); + void (*transfer)(void *self, size_t len, const uint8_t *src, uint8_t *dest); +} mp_spi_proto_t; + +typedef struct _mp_soft_spi_obj_t { + uint32_t delay_half; // microsecond delay for half SCK period + uint8_t polarity; + uint8_t phase; + mp_hal_pin_obj_t sck; + mp_hal_pin_obj_t mosi; + mp_hal_pin_obj_t miso; +} mp_soft_spi_obj_t; + +extern const mp_spi_proto_t mp_soft_spi_proto; + +int mp_soft_spi_ioctl(void *self, uint32_t cmd); +void mp_soft_spi_transfer(void *self, size_t len, const uint8_t *src, uint8_t *dest); + +#endif // MICROPY_INCLUDED_DRIVERS_BUS_SPI_H diff --git a/drivers/dht/dht.py b/drivers/dht/dht.py new file mode 100644 index 0000000000..eed61df7c9 --- /dev/null +++ b/drivers/dht/dht.py @@ -0,0 +1,35 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +try: + from esp import dht_readinto +except: + from pyb import dht_readinto + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: + raise Exception("checksum error") + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/extmod/machine_signal.c b/extmod/machine_signal.c index 78d0c3feef..3f9f5af947 100644 --- a/extmod/machine_signal.c +++ b/extmod/machine_signal.c @@ -58,7 +58,7 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t // If first argument isn't a Pin-like object, we filter out "invert" // from keyword arguments and pass them all to the exported Pin // constructor to create one. - mp_obj_t pin_args[n_args + n_kw * 2]; + mp_obj_t *pin_args = mp_local_alloc((n_args + n_kw * 2) * sizeof(mp_obj_t)); memcpy(pin_args, args, n_args * sizeof(mp_obj_t)); const mp_obj_t *src = args + n_args; mp_obj_t *dst = pin_args + n_args; @@ -88,6 +88,8 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t // will just ignore it as set a concrete type. If not, we'd need // to expose port's "default" pin type too. pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args); + + mp_local_free(pin_args); } else #endif diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c index a67d294baf..f0c4896c2e 100644 --- a/extmod/machine_spi.c +++ b/extmod/machine_spi.c @@ -38,61 +38,6 @@ #define MICROPY_PY_MACHINE_SPI_LSB (1) #endif -void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { - mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in; - uint32_t delay_half = self->delay_half; - - // only MSB transfer is implemented - - // If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured - // delay_half is equal to this value, then the software SPI implementation - // will run as fast as possible, limited only by CPU speed and GPIO time. - #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY - if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) { - for (size_t i = 0; i < len; ++i) { - uint8_t data_out = src[i]; - uint8_t data_in = 0; - for (int j = 0; j < 8; ++j, data_out <<= 1) { - mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); - mp_hal_pin_write(self->sck, 1 - self->polarity); - data_in = (data_in << 1) | mp_hal_pin_read(self->miso); - mp_hal_pin_write(self->sck, self->polarity); - } - if (dest != NULL) { - dest[i] = data_in; - } - } - return; - } - #endif - - for (size_t i = 0; i < len; ++i) { - uint8_t data_out = src[i]; - uint8_t data_in = 0; - for (int j = 0; j < 8; ++j, data_out <<= 1) { - mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); - if (self->phase == 0) { - mp_hal_delay_us_fast(delay_half); - mp_hal_pin_write(self->sck, 1 - self->polarity); - } else { - mp_hal_pin_write(self->sck, 1 - self->polarity); - mp_hal_delay_us_fast(delay_half); - } - data_in = (data_in << 1) | mp_hal_pin_read(self->miso); - if (self->phase == 0) { - mp_hal_delay_us_fast(delay_half); - mp_hal_pin_write(self->sck, self->polarity); - } else { - mp_hal_pin_write(self->sck, self->polarity); - mp_hal_delay_us_fast(delay_half); - } - } - if (dest != NULL) { - dest[i] = data_in; - } - } -} - /******************************************************************************/ // MicroPython bindings for generic machine.SPI @@ -199,9 +144,9 @@ MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table); // Implementation of soft SPI STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) { - #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY - if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) { - return MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE; + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) { + return MICROPY_HW_SOFTSPI_MAX_BAUDRATE; } else #endif { @@ -210,9 +155,9 @@ STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) { } STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) { - #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY - if (baudrate >= MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE) { - return MICROPY_PY_MACHINE_SPI_MIN_DELAY; + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE) { + return MICROPY_HW_SOFTSPI_MIN_DELAY; } else #endif { @@ -229,8 +174,8 @@ STATIC void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u," " sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")", - baudrate_from_delay_half(self->delay_half), self->polarity, self->phase, - mp_hal_pin_name(self->sck), mp_hal_pin_name(self->mosi), mp_hal_pin_name(self->miso)); + baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase, + mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso)); } STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -253,9 +198,9 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n self->base.type = &mp_machine_soft_spi_type; // set parameters - self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); - self->polarity = args[ARG_polarity].u_int; - self->phase = args[ARG_phase].u_int; + self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); + self->spi.polarity = args[ARG_polarity].u_int; + self->spi.phase = args[ARG_phase].u_int; if (args[ARG_bits].u_int != 8) { mp_raise_ValueError("bits must be 8"); } @@ -267,15 +212,12 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n || args[ARG_miso].u_obj == MP_OBJ_NULL) { mp_raise_ValueError("must specify all of sck/mosi/miso"); } - self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); - self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); - self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); + self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); + self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); + self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); - // configure pins - mp_hal_pin_write(self->sck, self->polarity); - mp_hal_pin_output(self->sck); - mp_hal_pin_output(self->mosi); - mp_hal_pin_input(self->miso); + // configure bus + mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT); return MP_OBJ_FROM_PTR(self); } @@ -296,32 +238,34 @@ STATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); if (args[ARG_baudrate].u_int != -1) { - self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); + self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); } if (args[ARG_polarity].u_int != -1) { - self->polarity = args[ARG_polarity].u_int; + self->spi.polarity = args[ARG_polarity].u_int; } if (args[ARG_phase].u_int != -1) { - self->phase = args[ARG_phase].u_int; + self->spi.phase = args[ARG_phase].u_int; } if (args[ARG_sck].u_obj != MP_OBJ_NULL) { - self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); + self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); } if (args[ARG_mosi].u_obj != MP_OBJ_NULL) { - self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); + self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); } if (args[ARG_miso].u_obj != MP_OBJ_NULL) { - self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); + self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); } - // configure pins - mp_hal_pin_write(self->sck, self->polarity); - mp_hal_pin_output(self->sck); - mp_hal_pin_output(self->mosi); - mp_hal_pin_input(self->miso); + // configure bus + mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT); } -STATIC const mp_machine_spi_p_t mp_machine_soft_spi_p = { +STATIC void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in; + mp_soft_spi_transfer(&self->spi, len, src, dest); +} + +const mp_machine_spi_p_t mp_machine_soft_spi_p = { .init = mp_machine_soft_spi_init, .deinit = NULL, .transfer = mp_machine_soft_spi_transfer, diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h index e24e41eb3d..db21e1cd31 100644 --- a/extmod/machine_spi.h +++ b/extmod/machine_spi.h @@ -28,6 +28,7 @@ #include "py/obj.h" #include "py/mphal.h" +#include "drivers/bus/spi.h" // SPI protocol typedef struct _mp_machine_spi_p_t { @@ -38,19 +39,13 @@ typedef struct _mp_machine_spi_p_t { typedef struct _mp_machine_soft_spi_obj_t { mp_obj_base_t base; - uint32_t delay_half; // microsecond delay for half SCK period - uint8_t polarity; - uint8_t phase; - mp_hal_pin_obj_t sck; - mp_hal_pin_obj_t mosi; - mp_hal_pin_obj_t miso; + mp_soft_spi_obj_t spi; } mp_machine_soft_spi_obj_t; +extern const mp_machine_spi_p_t mp_machine_soft_spi_p; extern const mp_obj_type_t mp_machine_soft_spi_type; extern const mp_obj_dict_t mp_machine_spi_locals_dict; -void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest); - mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj); diff --git a/extmod/modbtree.c b/extmod/modbtree.c index 5c13115328..8b76885809 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -282,7 +282,7 @@ STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_btree_t *self = MP_OBJ_TO_PTR(lhs_in); switch (op) { - case MP_BINARY_OP_IN: { + case MP_BINARY_OP_CONTAINS: { DBT key, val; key.data = (void*)mp_obj_str_get_data(rhs_in, &key.size); int res = __bt_get(self->db, &key, &val, 0); diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 20e40d5791..a7f6ba905f 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -54,7 +54,9 @@ typedef struct _mp_framebuf_p_t { // constants for formats #define FRAMEBUF_MVLSB (0) #define FRAMEBUF_RGB565 (1) +#define FRAMEBUF_GS2_HMSB (5) #define FRAMEBUF_GS4_HMSB (2) +#define FRAMEBUF_GS8 (6) #define FRAMEBUF_MHLSB (3) #define FRAMEBUF_MHMSB (4) @@ -130,6 +132,30 @@ STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, i } } +// Functions for GS2_HMSB format + +STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2]; + uint8_t shift = (x & 0x3) << 1; + uint8_t mask = 0x3 << shift; + uint8_t color = (col & 0x3) << shift; + *pixel = color | (*pixel & (~mask)); +} + +STATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + uint8_t pixel = ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2]; + uint8_t shift = (x & 0x3) << 1; + return (pixel >> shift) & 0x3; +} + +STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + for (int xx=x; xx < x+w; xx++) { + for (int yy=y; yy < y+h; yy++) { + gs2_hmsb_setpixel(fb, xx, yy, col); + } + } +} + // Functions for GS4_HMSB format STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { @@ -181,10 +207,31 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, } } +// Functions for GS8 format + +STATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)]; + *pixel = col & 0xff; +} + +STATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + return ((uint8_t*)fb->buf)[(x + y * fb->stride)]; +} + +STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)]; + while (h--) { + memset(pixel, col, w); + pixel += fb->stride; + } +} + STATIC mp_framebuf_p_t formats[] = { [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect}, [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect}, + [FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect}, [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect}, + [FRAMEBUF_GS8] = {gs8_setpixel, gs8_getpixel, gs8_fill_rect}, [FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, [FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, }; @@ -240,9 +287,14 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size case FRAMEBUF_MHMSB: o->stride = (o->stride + 7) & ~7; break; + case FRAMEBUF_GS2_HMSB: + o->stride = (o->stride + 3) & ~3; + break; case FRAMEBUF_GS4_HMSB: o->stride = (o->stride + 1) & ~1; break; + case FRAMEBUF_GS8: + break; default: mp_raise_ValueError("invalid format"); } @@ -579,7 +631,9 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_MVLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_VLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) }, { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) }, + { MP_ROM_QSTR(MP_QSTR_GS8), MP_ROM_INT(FRAMEBUF_GS8) }, { MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) }, }; diff --git a/extmod/modlwip.c b/extmod/modlwip.c index bbb01b5d76..dfb5de9e40 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -38,13 +38,18 @@ #include "lib/netutils/netutils.h" #include "lwip/init.h" -#include "lwip/timers.h" #include "lwip/tcp.h" #include "lwip/udp.h" //#include "lwip/raw.h" #include "lwip/dns.h" -#include "lwip/tcp_impl.h" #include "lwip/igmp.h" +#if LWIP_VERSION_MAJOR < 2 +#include "lwip/timers.h" +#include "lwip/tcp_impl.h" +#else +#include "lwip/timeouts.h" +#include "lwip/priv/tcp_priv.h" +#endif #if 0 // print debugging info #define DEBUG_printf DEBUG_printf @@ -171,11 +176,16 @@ STATIC const mp_obj_type_t lwip_slip_type = { // Table to convert lwIP err_t codes to socket errno codes, from the lwIP // socket API. +// lwIP 2 changed LWIP_VERSION and it can no longer be used in macros, +// so we define our own equivalent version that can. +#define LWIP_VERSION_MACRO (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 \ + | LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) + // Extension to lwIP error codes #define _ERR_BADF -16 // TODO: We just know that change happened somewhere between 1.4.0 and 1.4.1, // investigate in more detail. -#if LWIP_VERSION < 0x01040100 +#if LWIP_VERSION_MACRO < 0x01040100 static const int error_lookup_table[] = { 0, /* ERR_OK 0 No error, everything OK. */ MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ @@ -196,7 +206,7 @@ static const int error_lookup_table[] = { MP_EALREADY, /* ERR_ISCONN -15 Already connected. */ MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ }; -#else +#elif LWIP_VERSION_MACRO < 0x02000000 static const int error_lookup_table[] = { 0, /* ERR_OK 0 No error, everything OK. */ MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ @@ -217,6 +227,30 @@ static const int error_lookup_table[] = { -1, /* ERR_IF -15 Low-level netif error */ MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ }; +#else +// Matches lwIP 2.0.3 +#undef _ERR_BADF +#define _ERR_BADF -17 +static const int error_lookup_table[] = { + 0, /* ERR_OK 0 No error, everything OK */ + MP_ENOMEM, /* ERR_MEM -1 Out of memory error */ + MP_ENOBUFS, /* ERR_BUF -2 Buffer error */ + MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem */ + MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + MP_EINVAL, /* ERR_VAL -6 Illegal value */ + MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block */ + MP_EADDRINUSE, /* ERR_USE -8 Address in use */ + MP_EALREADY, /* ERR_ALREADY -9 Already connecting */ + MP_EALREADY, /* ERR_ISCONN -10 Conn already established */ + MP_ENOTCONN, /* ERR_CONN -11 Not connected */ + -1, /* ERR_IF -12 Low-level netif error */ + MP_ECONNABORTED, /* ERR_ABRT -13 Connection aborted */ + MP_ECONNRESET, /* ERR_RST -14 Connection reset */ + MP_ENOTCONN, /* ERR_CLSD -15 Connection closed */ + MP_EIO, /* ERR_ARG -16 Illegal argument. */ + MP_EBADF, /* _ERR_BADF -17 Closed socket (null pcb) */ +}; #endif /*******************************************************************************/ @@ -276,7 +310,12 @@ static inline void exec_user_callback(lwip_socket_obj_t *socket) { // Callback for incoming UDP packets. We simply stash the packet and the source address, // in case we need it for recvfrom. -STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { +#if LWIP_VERSION_MAJOR < 2 +STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) +#else +STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +#endif +{ lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; if (socket->incoming.pbuf != NULL) { @@ -498,6 +537,11 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY); + // If the output buffer is getting full then send the data to the lower layers + if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) { + err = tcp_output(socket->pcb.tcp); + } + if (err != ERR_OK) { *_errno = error_lookup_table[-err]; return MP_STREAM_ERROR; @@ -632,42 +676,6 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s return socket; } -STATIC mp_obj_t lwip_socket_close(mp_obj_t self_in) { - lwip_socket_obj_t *socket = self_in; - bool socket_is_listener = false; - - if (socket->pcb.tcp == NULL) { - return mp_const_none; - } - switch (socket->type) { - case MOD_NETWORK_SOCK_STREAM: { - if (socket->pcb.tcp->state == LISTEN) { - socket_is_listener = true; - } - if (tcp_close(socket->pcb.tcp) != ERR_OK) { - DEBUG_printf("lwip_close: had to call tcp_abort()\n"); - tcp_abort(socket->pcb.tcp); - } - break; - } - case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; - //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; - } - socket->pcb.tcp = NULL; - socket->state = _ERR_BADF; - if (socket->incoming.pbuf != NULL) { - if (!socket_is_listener) { - pbuf_free(socket->incoming.pbuf); - } else { - tcp_abort(socket->incoming.connection); - } - socket->incoming.pbuf = NULL; - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_close_obj, lwip_socket_close); - STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { lwip_socket_obj_t *socket = self_in; @@ -715,6 +723,9 @@ STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { socket->pcb.tcp = new_pcb; tcp_accept(new_pcb, _lwip_tcp_accept); + // Socket is no longer considered "new" for purposes of polling + socket->state = STATE_CONNECTING; + return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen); @@ -1163,17 +1174,60 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ ret |= MP_STREAM_POLL_RD; } - if (flags & MP_STREAM_POLL_WR && tcp_sndbuf(socket->pcb.tcp) > 0) { + // Note: pcb.tcp==NULL if state<0, and in this case we can't call tcp_sndbuf + if (flags & MP_STREAM_POLL_WR && socket->pcb.tcp != NULL && tcp_sndbuf(socket->pcb.tcp) > 0) { ret |= MP_STREAM_POLL_WR; } - if (socket->state == STATE_PEER_CLOSED) { + if (socket->state == STATE_NEW) { + // New sockets are not connected so set HUP + ret |= flags & MP_STREAM_POLL_HUP; + } else if (socket->state == STATE_PEER_CLOSED) { // Peer-closed socket is both readable and writable: read will // return EOF, write - error. Without this poll will hang on a // socket which was closed by peer. ret |= flags & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR); + } else if (socket->state == ERR_RST) { + // Socket was reset by peer, a write will return an error + ret |= flags & (MP_STREAM_POLL_WR | MP_STREAM_POLL_HUP); + } else if (socket->state < 0) { + // Socket in some other error state, use catch-all ERR flag + // TODO: may need to set other return flags here + ret |= flags & MP_STREAM_POLL_ERR; } + } else if (request == MP_STREAM_CLOSE) { + bool socket_is_listener = false; + + if (socket->pcb.tcp == NULL) { + return 0; + } + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: { + if (socket->pcb.tcp->state == LISTEN) { + socket_is_listener = true; + } + if (tcp_close(socket->pcb.tcp) != ERR_OK) { + DEBUG_printf("lwip_close: had to call tcp_abort()\n"); + tcp_abort(socket->pcb.tcp); + } + break; + } + case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break; + //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break; + } + socket->pcb.tcp = NULL; + socket->state = _ERR_BADF; + if (socket->incoming.pbuf != NULL) { + if (!socket_is_listener) { + pbuf_free(socket->incoming.pbuf); + } else { + tcp_abort(socket->incoming.connection); + } + socket->incoming.pbuf = NULL; + } + ret = 0; + } else { *errcode = MP_EINVAL; ret = MP_STREAM_ERROR; @@ -1183,8 +1237,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ } STATIC const mp_rom_map_elem_t lwip_socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&lwip_socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&lwip_socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&lwip_socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&lwip_socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&lwip_socket_accept_obj) }, @@ -1278,7 +1332,12 @@ typedef struct _getaddrinfo_state_t { } getaddrinfo_state_t; // Callback for incoming DNS requests. -STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) { +#if LWIP_VERSION_MAJOR < 2 +STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) +#else +STATIC void lwip_getaddrinfo_cb(const char *name, const ip_addr_t *ipaddr, void *arg) +#endif +{ getaddrinfo_state_t *state = arg; if (ipaddr != NULL) { state->status = 1; @@ -1291,14 +1350,33 @@ STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) // lwip.getaddrinfo STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) { - if (n_args > 2) { - mp_warning("getaddrinfo constraints not supported"); - } - mp_obj_t host_in = args[0], port_in = args[1]; const char *host = mp_obj_str_get_str(host_in); mp_int_t port = mp_obj_get_int(port_in); + // If constraints were passed then check they are compatible with the supported params + if (n_args > 2) { + mp_int_t family = mp_obj_get_int(args[2]); + mp_int_t type = 0; + mp_int_t proto = 0; + mp_int_t flags = 0; + if (n_args > 3) { + type = mp_obj_get_int(args[3]); + if (n_args > 4) { + proto = mp_obj_get_int(args[4]); + if (n_args > 5) { + flags = mp_obj_get_int(args[5]); + } + } + } + if (!((family == 0 || family == MOD_NETWORK_AF_INET) + && (type == 0 || type == MOD_NETWORK_SOCK_STREAM) + && proto == 0 + && flags == 0)) { + mp_warning("unsupported getaddrinfo constraints"); + } + } + getaddrinfo_state_t state; state.status = 0; @@ -1331,7 +1409,7 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) { tuple->items[4] = netutils_format_inet_addr((uint8_t*)&state.ipaddr, port, NETUTILS_BIG); return mp_obj_new_list(1, (mp_obj_t*)&tuple); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo); // Debug functions diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index 7ae42a15f1..d062271bb2 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -31,8 +31,19 @@ #if MICROPY_PY_UHASHLIB +#if MICROPY_PY_UHASHLIB_SHA256 + +#if MICROPY_SSL_MBEDTLS +#include "mbedtls/sha256.h" +#else #include "crypto-algorithms/sha256.h" +#endif + +#endif + #if MICROPY_PY_UHASHLIB_SHA1 + +#if MICROPY_SSL_AXTLS #include "lib/axtls/crypto/crypto.h" #endif @@ -42,6 +53,13 @@ static void check_not_unicode(const mp_obj_t arg) { mp_raise_TypeError("a bytes-like object is required"); } #endif + +#if MICROPY_SSL_MBEDTLS +#include "mbedtls/sha1.h" +#endif + +#endif + } typedef struct _mp_obj_hash_t { @@ -49,35 +67,53 @@ typedef struct _mp_obj_hash_t { char state[0]; } mp_obj_hash_t; -STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg); +#if MICROPY_PY_UHASHLIB_SHA256 +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg); -STATIC mp_obj_t hash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +#if MICROPY_SSL_MBEDTLS + +STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context)); + o->base.type = type; + mbedtls_sha256_init((mbedtls_sha256_context*)&o->state); + mbedtls_sha256_starts((mbedtls_sha256_context*)&o->state, 0); + if (n_args == 1) { + uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_sha256_update((mbedtls_sha256_context*)&self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 32); + mbedtls_sha256_finish((mbedtls_sha256_context*)&self->state, (unsigned char *)vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} + +#else + +STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX)); o->base.type = type; sha256_init((CRYAL_SHA256_CTX*)o->state); if (n_args == 1) { - hash_update(MP_OBJ_FROM_PTR(o), args[0]); + uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]); } return MP_OBJ_FROM_PTR(o); } -#if MICROPY_PY_UHASHLIB_SHA1 -STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg); - -STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, 1, false); - mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX)); - o->base.type = type; - SHA1_Init((SHA1_CTX*)o->state); - if (n_args == 1) { - sha1_update(MP_OBJ_FROM_PTR(o), args[0]); - } - return MP_OBJ_FROM_PTR(o); -} -#endif - -STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) { +STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { check_not_unicode(arg); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; @@ -85,10 +121,50 @@ STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) { sha256_update((CRYAL_SHA256_CTX*)self->state, bufinfo.buf, bufinfo.len); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update); + +STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, SHA256_BLOCK_SIZE); + sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest); + +STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_digest_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(uhashlib_sha256_locals_dict, uhashlib_sha256_locals_dict_table); + +STATIC const mp_obj_type_t uhashlib_sha256_type = { + { &mp_type_type }, + .name = MP_QSTR_sha256, + .make_new = uhashlib_sha256_make_new, + .locals_dict = (void*)&uhashlib_sha256_locals_dict, +}; +#endif #if MICROPY_PY_UHASHLIB_SHA1 -STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg); + +#if MICROPY_SSL_AXTLS +STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX)); + o->base.type = type; + SHA1_Init((SHA1_CTX*)o->state); + if (n_args == 1) { + uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { check_not_unicode(arg); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; @@ -96,73 +172,83 @@ STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) { SHA1_Update((SHA1_CTX*)self->state, bufinfo.buf, bufinfo.len); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(sha1_update_obj, sha1_update); -#endif -STATIC mp_obj_t hash_digest(mp_obj_t self_in) { - mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); - vstr_t vstr; - vstr_init_len(&vstr, SHA256_BLOCK_SIZE); - sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf); - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -} -MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest); - -#if MICROPY_PY_UHASHLIB_SHA1 -STATIC mp_obj_t sha1_digest(mp_obj_t self_in) { +STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); vstr_t vstr; vstr_init_len(&vstr, SHA1_SIZE); SHA1_Final((byte*)vstr.buf, (SHA1_CTX*)self->state); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } -MP_DEFINE_CONST_FUN_OBJ_1(sha1_digest_obj, sha1_digest); #endif -STATIC const mp_rom_map_elem_t hash_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hash_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hash_digest_obj) }, +#if MICROPY_SSL_MBEDTLS +STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context)); + o->base.type = type; + mbedtls_sha1_init((mbedtls_sha1_context*)o->state); + mbedtls_sha1_starts((mbedtls_sha1_context*)o->state); + if (n_args == 1) { + uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + mbedtls_sha1_update((mbedtls_sha1_context*)self->state, bufinfo.buf, bufinfo.len); + return mp_const_none; +} + +STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { + mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); + vstr_t vstr; + vstr_init_len(&vstr, 20); + mbedtls_sha1_finish((mbedtls_sha1_context*)self->state, (byte*)vstr.buf); + mbedtls_sha1_free((mbedtls_sha1_context*)self->state); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +#endif + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest); + +STATIC const mp_rom_map_elem_t uhashlib_sha1_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha1_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha1_digest_obj) }, }; +STATIC MP_DEFINE_CONST_DICT(uhashlib_sha1_locals_dict, uhashlib_sha1_locals_dict_table); -STATIC MP_DEFINE_CONST_DICT(hash_locals_dict, hash_locals_dict_table); - -STATIC const mp_obj_type_t sha256_type = { - { &mp_type_type }, - .name = MP_QSTR_sha256, - .make_new = hash_make_new, - .locals_dict = (void*)&hash_locals_dict, -}; - -#if MICROPY_PY_UHASHLIB_SHA1 -STATIC const mp_rom_map_elem_t sha1_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&sha1_update_obj) }, - { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&sha1_digest_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(sha1_locals_dict, sha1_locals_dict_table); - -STATIC const mp_obj_type_t sha1_type = { +STATIC const mp_obj_type_t uhashlib_sha1_type = { { &mp_type_type }, .name = MP_QSTR_sha1, - .make_new = sha1_make_new, - .locals_dict = (void*)&sha1_locals_dict, + .make_new = uhashlib_sha1_make_new, + .locals_dict = (void*)&uhashlib_sha1_locals_dict, }; #endif -STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = { +STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_hashlib) }, - { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&sha256_type) }, + #if MICROPY_PY_UHASHLIB_SHA256 + { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&uhashlib_sha256_type) }, + #endif #if MICROPY_PY_UHASHLIB_SHA1 - { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&sha1_type) }, + { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&uhashlib_sha1_type) }, #endif }; -STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table); +STATIC MP_DEFINE_CONST_DICT(mp_module_uhashlib_globals, mp_module_uhashlib_globals_table); const mp_obj_module_t mp_module_uhashlib = { .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&mp_module_hashlib_globals, + .globals = (mp_obj_dict_t*)&mp_module_uhashlib_globals, }; +#if MICROPY_PY_UHASHLIB_SHA256 #include "crypto-algorithms/sha256.c" +#endif #endif //MICROPY_PY_UHASHLIB diff --git a/extmod/modujson.c b/extmod/modujson.c index f14682d26f..830b588fdc 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -34,6 +34,14 @@ #if MICROPY_PY_UJSON +STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) { + mp_get_stream_raise(stream, MP_STREAM_OP_WRITE); + mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor}; + mp_obj_print_helper(&print, obj, PRINT_JSON); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump); + STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { vstr_t vstr; mp_print_t print; @@ -166,7 +174,7 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { goto fail; } S_NEXT(s); - next = mp_obj_new_str(vstr.buf, vstr.len, false); + next = mp_obj_new_str(vstr.buf, vstr.len); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { @@ -283,6 +291,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads); STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) }, + { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_ujson_dump_obj) }, { MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) }, { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) }, { MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) }, diff --git a/extmod/modure.c b/extmod/modure.c index 78de4706d2..31c2b98647 100644 --- a/extmod/modure.c +++ b/extmod/modure.c @@ -144,7 +144,7 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) { } mp_obj_t retval = mp_obj_new_list(0, NULL); - const char **caps = alloca(caps_num * sizeof(char*)); + const char **caps = mp_local_alloc(caps_num * sizeof(char*)); while (true) { // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char memset((char**)caps, 0, caps_num * sizeof(char*)); @@ -165,6 +165,8 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) { break; } } + // cast is a workaround for a bug in msvc (see above) + mp_local_free((char**)caps); mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, subj.end - subj.begin); mp_obj_list_append(retval, s); diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index 3ad65ebf32..475d3f0ea4 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -44,6 +44,8 @@ typedef struct _mp_obj_ssl_socket_t { } mp_obj_ssl_socket_t; struct ssl_args { + mp_arg_val_t key; + mp_arg_val_t cert; mp_arg_val_t server_side; mp_arg_val_t server_hostname; }; @@ -62,10 +64,28 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { o->sock = sock; uint32_t options = SSL_SERVER_VERIFY_LATER; + if (args->key.u_obj != mp_const_none) { + options |= SSL_NO_DEFAULT_KEY; + } if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) { mp_raise_OSError(MP_EINVAL); } + if (args->key.u_obj != mp_const_none) { + size_t len; + const byte *data = (const byte*)mp_obj_str_get_data(args->key.u_obj, &len); + int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL); + if (res != SSL_OK) { + mp_raise_ValueError("invalid key"); + } + + data = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &len); + res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL); + if (res != SSL_OK) { + mp_raise_ValueError("invalid cert"); + } + } + if (args->server_side.u_bool) { o->ssl_sock = ssl_server_new(o->ssl_ctx, (long)sock); } else { @@ -113,7 +133,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc mp_int_t r = ssl_read(o->ssl_sock, &o->buf); if (r == SSL_OK) { // SSL_OK from ssl_read() means "everything is ok, but there's - // not user data yet. So, we just keep reading. + // no user data yet". So, we just keep reading. continue; } if (r < 0) { @@ -121,6 +141,9 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc // EOF return 0; } + if (r == SSL_EAGAIN) { + r = MP_EAGAIN; + } *errcode = r; return MP_STREAM_ERROR; } @@ -152,6 +175,25 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in return r; } +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + if (self->ssl_sock != NULL) { + ssl_free(self->ssl_sock); + ssl_ctx_free(self->ssl_ctx); + self->ssl_sock = NULL; + mp_stream_close(self->sock); + } + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { // Currently supports only blocking mode (void)self_in; @@ -162,28 +204,15 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); - if (self->ssl_sock != NULL) { - ssl_free(self->ssl_sock); - ssl_ctx_free(self->ssl_ctx); - self->ssl_sock = NULL; - return mp_stream_close(self->sock); - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); - STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, #if MICROPY_PY_USSL_FINALISER - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, #endif }; @@ -192,6 +221,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab STATIC const mp_stream_p_t ussl_socket_stream_p = { .read = socket_read, .write = socket_write, + .ioctl = socket_ioctl, }; STATIC const mp_obj_type_t ussl_socket_type = { @@ -208,6 +238,8 @@ STATIC const mp_obj_type_t ussl_socket_type = { STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // TODO: Implement more args static const mp_arg_t allowed_args[] = { + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index 69a64d2f7a..08807d20ba 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -73,19 +73,10 @@ STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, cons } #endif -// TODO: FIXME! -STATIC int null_entropy_func(void *data, unsigned char *output, size_t len) { - (void)data; - (void)output; - (void)len; - // enjoy random bytes - return 0; -} - STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { mp_obj_t sock = *(mp_obj_t*)ctx; - const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_WRITE); + const mp_stream_p_t *sock_stream = mp_get_stream(sock); int err; mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err); @@ -102,7 +93,7 @@ STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { mp_obj_t sock = *(mp_obj_t*)ctx; - const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_READ); + const mp_stream_p_t *sock_stream = mp_get_stream(sock); int err; mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err); @@ -118,12 +109,16 @@ STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { + // Verify the socket object has the full stream protocol + mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + #if MICROPY_PY_USSL_FINALISER mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); #else mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); #endif o->base.type = &ussl_socket_type; + o->sock = sock; int ret; mbedtls_ssl_init(&o->ssl); @@ -139,10 +134,9 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { mbedtls_entropy_init(&o->entropy); const byte seed[] = "upy"; - ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, null_entropy_func/*mbedtls_entropy_func*/, &o->entropy, seed, sizeof(seed)); + ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed)); if (ret != 0) { - printf("ret=%d\n", ret); - assert(0); + goto cleanup; } ret = mbedtls_ssl_config_defaults(&o->conf, @@ -150,7 +144,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret != 0) { - assert(0); + goto cleanup; } mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); @@ -161,18 +155,17 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { ret = mbedtls_ssl_setup(&o->ssl, &o->conf); if (ret != 0) { - assert(0); + goto cleanup; } if (args->server_hostname.u_obj != mp_const_none) { const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj); ret = mbedtls_ssl_set_hostname(&o->ssl, sni); if (ret != 0) { - assert(0); + goto cleanup; } } - o->sock = sock; mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); if (args->key.u_obj != MP_OBJ_NULL) { @@ -194,13 +187,27 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - //assert(0); printf("mbedtls_ssl_handshake error: -%x\n", -ret); - mp_raise_OSError(MP_EIO); + goto cleanup; } } return o; + +cleanup: + mbedtls_pk_free(&o->pkey); + mbedtls_x509_crt_free(&o->cert); + mbedtls_x509_crt_free(&o->cacert); + mbedtls_ssl_free(&o->ssl); + mbedtls_ssl_config_free(&o->conf); + mbedtls_ctr_drbg_free(&o->ctr_drbg); + mbedtls_entropy_free(&o->entropy); + + if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { + mp_raise_OSError(MP_ENOMEM); + } else { + mp_raise_OSError(MP_EIO); + } } STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) { @@ -261,20 +268,26 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + mbedtls_pk_free(&self->pkey); + mbedtls_x509_crt_free(&self->cert); + mbedtls_x509_crt_free(&self->cacert); + mbedtls_ssl_free(&self->ssl); + mbedtls_ssl_config_free(&self->conf); + mbedtls_ctr_drbg_free(&self->ctr_drbg); + mbedtls_entropy_free(&self->entropy); + mp_stream_close(self->sock); + return 0; - mbedtls_pk_free(&self->pkey); - mbedtls_x509_crt_free(&self->cert); - mbedtls_x509_crt_free(&self->cacert); - mbedtls_ssl_free(&self->ssl); - mbedtls_ssl_config_free(&self->conf); - mbedtls_ctr_drbg_free(&self->ctr_drbg); - mbedtls_entropy_free(&self->entropy); - - return mp_stream_close(self->sock); + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, @@ -282,9 +295,9 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, #if MICROPY_PY_USSL_FINALISER - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) }, }; @@ -294,6 +307,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab STATIC const mp_stream_p_t ussl_socket_stream_p = { .read = socket_read, .write = socket_write, + .ioctl = socket_ioctl, }; STATIC const mp_obj_type_t ussl_socket_type = { diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index 3d2ab88af1..0d2366bea1 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -53,7 +53,7 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) { p -= offsetof(mp_obj_decompio_t, decomp); mp_obj_decompio_t *self = (mp_obj_decompio_t*)p; - const mp_stream_p_t *stream = mp_get_stream_raise(self->src_stream, MP_STREAM_OP_READ); + const mp_stream_p_t *stream = mp_get_stream(self->src_stream); int err; byte c; mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err); @@ -68,6 +68,7 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) { STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 2, false); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ); mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t); o->base.type = type; memset(&o->decomp, 0, sizeof(o->decomp)); diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 38b88821b2..48b49bfc4f 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -76,7 +76,7 @@ STATIC char denied_prompt[] = "\r\nAccess denied\r\n"; STATIC char webrepl_passwd[10]; STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) { - const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + const mp_stream_p_t *sock_stream = mp_get_stream(websock); int err; int old_opts = sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, FRAME_BIN, &err); sock_stream->write(websock, buf, len, &err); @@ -86,7 +86,7 @@ STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) { #define SSTR(s) s, sizeof(s) - 1 STATIC void write_webrepl_str(mp_obj_t websock, const char *str, int sz) { int err; - const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + const mp_stream_p_t *sock_stream = mp_get_stream(websock); sock_stream->write(websock, str, sz, &err); } @@ -110,8 +110,7 @@ STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_ } STATIC int write_file_chunk(mp_obj_webrepl_t *self) { - const mp_stream_p_t *file_stream = - mp_get_stream_raise(self->cur_file, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file); byte readbuf[2 + 256]; int err; mp_uint_t out_sz = file_stream->read(self->cur_file, readbuf + 2, sizeof(readbuf) - 2, &err); @@ -141,7 +140,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) { // Handle operations requiring opened file mp_obj_t open_args[2] = { - mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname), false), + mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname)), MP_OBJ_NEW_QSTR(MP_QSTR_rb) }; @@ -181,7 +180,7 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int // We know that os.dupterm always calls with size = 1 assert(size == 1); mp_obj_webrepl_t *self = self_in; - const mp_stream_p_t *sock_stream = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ); + const mp_stream_p_t *sock_stream = mp_get_stream(self->sock); mp_uint_t out_sz = sock_stream->read(self->sock, buf, size, errcode); //DEBUG_printf("webrepl: Read %d initial bytes from websocket\n", out_sz); if (out_sz == 0 || out_sz == MP_STREAM_ERROR) { @@ -293,16 +292,24 @@ STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size // Don't forward output until passwd is entered return size; } - const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_WRITE); + const mp_stream_p_t *stream_p = mp_get_stream(self->sock); return stream_p->write(self->sock, buf, size, errcode); } -STATIC mp_obj_t webrepl_close(mp_obj_t self_in) { - mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(self_in); - // TODO: This is a place to do cleanup - return mp_stream_close(self->sock); +STATIC mp_uint_t webrepl_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + // TODO: This is a place to do cleanup + mp_stream_close(self->sock); + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_close_obj, webrepl_close); STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) { size_t len; @@ -319,13 +326,14 @@ STATIC const mp_rom_map_elem_t webrepl_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&webrepl_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(webrepl_locals_dict, webrepl_locals_dict_table); STATIC const mp_stream_p_t webrepl_stream_p = { .read = webrepl_read, .write = webrepl_write, + .ioctl = webrepl_ioctl, }; STATIC const mp_obj_type_t webrepl_type = { diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c index a651164b2f..c556f2b770 100644 --- a/extmod/modwebsocket.c +++ b/extmod/modwebsocket.c @@ -59,6 +59,7 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 2, false); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); mp_obj_websocket_t *o = m_new_obj(mp_obj_websocket_t); o->base.type = type; o->sock = args[0]; @@ -75,7 +76,7 @@ STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, siz STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); - const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ); + const mp_stream_p_t *stream_p = mp_get_stream(self->sock); while (1) { if (self->to_recv != 0) { mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode); @@ -256,6 +257,11 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); switch (request) { + case MP_STREAM_CLOSE: + // TODO: Send close signaling to the other side, otherwise it's + // abrupt close (connection abort). + mp_stream_close(self->sock); + return 0; case MP_STREAM_GET_DATA_OPTS: return self->ws_flags & FRAME_OPCODE_MASK; case MP_STREAM_SET_DATA_OPTS: { @@ -269,21 +275,13 @@ STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t } } -STATIC mp_obj_t websocket_close(mp_obj_t self_in) { - mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); - // TODO: Send close signaling to the other side, otherwise it's - // abrupt close (connection abort). - return mp_stream_close(self->sock); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(websocket_close_obj, websocket_close); - STATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&websocket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table); diff --git a/extmod/re1.5/compilecode.c b/extmod/re1.5/compilecode.c index 3267a4190d..a685a508a0 100644 --- a/extmod/re1.5/compilecode.c +++ b/extmod/re1.5/compilecode.c @@ -5,9 +5,9 @@ #include "re1.5.h" #define INSERT_CODE(at, num, pc) \ - ((code ? memmove(code + at + num, code + at, pc - at) : (void)0), pc += num) + ((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num) #define REL(at, to) (to - at - 2) -#define EMIT(at, byte) (code ? (code[at] = byte) : (void)(at)) +#define EMIT(at, byte) (code ? (code[at] = byte) : (at)) #define PC (prog->bytelen) static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c index e5e6663b0a..0de26cbdd4 100644 --- a/extmod/uos_dupterm.c +++ b/extmod/uos_dupterm.c @@ -60,25 +60,29 @@ int mp_uos_dupterm_rx_chr(void) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_obj_t readinto_m[3]; - mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_readinto, readinto_m); - readinto_m[2] = MP_STATE_VM(dupterm_arr_obj); - mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m); - if (res == mp_const_none) { - nlr_pop(); - } else if (res == MP_OBJ_NEW_SMALL_INT(0)) { + byte buf[1]; + int errcode; + const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx])); + mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode); + if (out_sz == 0) { nlr_pop(); mp_uos_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL); + } else if (out_sz == MP_STREAM_ERROR) { + // errcode is valid + if (mp_is_nonblocking_error(errcode)) { + nlr_pop(); + } else { + mp_raise_OSError(errcode); + } } else { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(MP_STATE_VM(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ); + // read 1 byte nlr_pop(); - if (*(byte*)bufinfo.buf == mp_interrupt_char) { + if (buf[0] == mp_interrupt_char) { // Signal keyboard interrupt to be raised as soon as the VM resumes mp_keyboard_interrupt(); return -2; } - return *(byte*)bufinfo.buf; + return buf[0]; } } else { mp_uos_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", nlr.ret_val); @@ -96,18 +100,7 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) { } nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_obj_t write_m[3]; - mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_write, write_m); - - mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj)); - void *org_items = arr->items; - arr->items = (void*)str; - arr->len = len; - write_m[2] = MP_STATE_VM(dupterm_arr_obj); - mp_call_method_n_kw(1, 0, write_m); - arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj)); - arr->items = org_items; - arr->len = 1; + mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE); nlr_pop(); } else { mp_uos_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", nlr.ret_val); @@ -132,10 +125,8 @@ STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) { if (args[0] == mp_const_none) { MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL; } else { + mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); MP_STATE_VM(dupterm_objs[idx]) = args[0]; - if (MP_STATE_VM(dupterm_arr_obj) == MP_OBJ_NULL) { - MP_STATE_VM(dupterm_arr_obj) = mp_obj_new_bytearray(1, ""); - } } return previous_obj; diff --git a/extmod/vfs.c b/extmod/vfs.c index e83646d8de..cc794aad5b 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -124,21 +124,39 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) { if (vfs == MP_VFS_NONE || vfs == MP_VFS_ROOT) { return MP_IMPORT_STAT_NO_EXIST; } - #if MICROPY_VFS_FAT - // fast paths for known VFS types - if (mp_obj_get_type(vfs->obj) == &mp_fat_vfs_type) { - return fat_vfs_import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); + + // If the mounted object has the VFS protocol, call its import_stat helper + const mp_vfs_proto_t *proto = mp_obj_get_type(vfs->obj)->protocol; + if (proto != NULL) { + return proto->import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); + } + + // delegate to vfs.stat() method + mp_obj_t path_o = mp_obj_new_str(path_out, strlen(path_out)); + mp_obj_t stat; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + stat = mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_o); + nlr_pop(); + } else { + // assume an exception means that the path is not found + return MP_IMPORT_STAT_NO_EXIST; + } + mp_obj_t *items; + mp_obj_get_array_fixed_n(stat, 10, &items); + mp_int_t st_mode = mp_obj_get_int(items[0]); + if (st_mode & MP_S_IFDIR) { + return MP_IMPORT_STAT_DIR; + } else { + return MP_IMPORT_STAT_FILE; } - #endif - // TODO delegate to vfs.stat() method - return MP_IMPORT_STAT_NO_EXIST; } mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_readonly, ARG_mkfs }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} }, - { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} }, + { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} }, + { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} }, }; // parse args @@ -246,7 +264,7 @@ mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_vfs_mount_t *vfs = lookup_path((mp_obj_t)args[ARG_file].u_rom_obj, &args[ARG_file].u_obj); + mp_vfs_mount_t *vfs = lookup_path(args[ARG_file].u_obj, &args[ARG_file].u_obj); return mp_vfs_proxy_call(vfs, MP_QSTR_open, 2, (mp_obj_t*)&args); } MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open); @@ -261,7 +279,7 @@ mp_obj_t mp_vfs_chdir(mp_obj_t path_in) { // subsequent relative paths begin at the root of that VFS. for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { if (vfs->len == 1) { - mp_obj_t root = mp_obj_new_str("/", 1, false); + mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_); mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &root); break; } @@ -307,7 +325,7 @@ mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in) { self->cur.vfs = vfs->next; if (vfs->len == 1) { // vfs is mounted at root dir, delegate to it - mp_obj_t root = mp_obj_new_str("/", 1, false); + mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_); self->is_iter = true; self->cur.iter = mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &root); return mp_iternext(self->cur.iter); @@ -355,9 +373,7 @@ mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) { mp_obj_t dir_list = mp_obj_new_list(0, NULL); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { - mp_obj_t *items; - mp_obj_get_array_fixed_n(next, 3, &items); - mp_obj_list_append(dir_list, items[0]); + mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL)); } return dir_list; } diff --git a/extmod/vfs.h b/extmod/vfs.h index c20d6dcd47..5ab2067e5a 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -45,6 +45,11 @@ #define BP_IOCTL_SEC_COUNT (4) #define BP_IOCTL_SEC_SIZE (5) +// At the moment the VFS protocol just has import_stat, but could be extended to other methods +typedef struct _mp_vfs_proto_t { + mp_import_stat_t (*import_stat)(void *self, const char *path); +} mp_vfs_proto_t; + typedef struct _mp_vfs_mount_t { const char *str; // mount point with leading / size_t len; diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 81ca1e23dc..633c04389b 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -48,6 +48,21 @@ #define mp_obj_fat_vfs_t fs_user_mount_t +STATIC mp_import_stat_t fat_vfs_import_stat(void *vfs_in, const char *path) { + fs_user_mount_t *vfs = vfs_in; + FILINFO fno; + assert(vfs != NULL); + FRESULT res = f_stat(&vfs->fatfs, path, &fno); + if (res == FR_OK) { + if ((fno.fattrib & AM_DIR) != 0) { + return MP_IMPORT_STAT_DIR; + } else { + return MP_IMPORT_STAT_FILE; + } + } + return MP_IMPORT_STAT_NO_EXIST; +} + STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); @@ -70,9 +85,28 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_ mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count); } + // mount the block device so the VFS methods can be used + FRESULT res = f_mount(&vfs->fatfs); + if (res == FR_NO_FILESYSTEM) { + // don't error out if no filesystem, to let mkfs()/mount() create one if wanted + vfs->flags |= FSUSER_NO_FILESYSTEM; + } else if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + return MP_OBJ_FROM_PTR(vfs); } +#if _FS_REENTRANT +STATIC mp_obj_t fat_vfs_del(mp_obj_t self_in) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(self_in); + // f_umount only needs to be called to release the sync object + f_umount(&self->fatfs); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_del_obj, fat_vfs_del); +#endif + STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { // create new object fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in)); @@ -89,7 +123,52 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs); STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mkfs_fun_obj)); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); +typedef struct _mp_vfs_fat_ilistdir_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + bool is_str; + FF_DIR dir; +} mp_vfs_fat_ilistdir_it_t; + +STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { + mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); + + for (;;) { + FILINFO fno; + FRESULT res = f_readdir(&self->dir, &fno); + char *fn = fno.fname; + if (res != FR_OK || fn[0] == 0) { + // stop on error or end of dir + break; + } + + // Note that FatFS already filters . and .., so we don't need to + + // make 4-tuple with info about this entry + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); + if (self->is_str) { + t->items[0] = mp_obj_new_str(fn, strlen(fn)); + } else { + t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); + } + if (fno.fattrib & AM_DIR) { + // dir + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); + } else { + // file + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); + } + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number + t->items[3] = mp_obj_new_int_from_uint(fno.fsize); + + return MP_OBJ_FROM_PTR(t); + } + + // ignore error because we may be closing a second time + f_closedir(&self->dir); + + return MP_OBJ_STOP_ITERATION; +} STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) { mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]); @@ -104,7 +183,17 @@ STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) { path = ""; } - return fat_vfs_ilistdir2(self, path, is_str_type); + // Create a new iterator object to list the dir + mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = mp_vfs_fat_ilistdir_it_iternext; + iter->is_str = is_str_type; + FRESULT res = f_opendir(&self->fatfs, &iter->dir, path); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + return MP_OBJ_FROM_PTR(iter); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_ilistdir_obj, 1, 2, fat_vfs_ilistdir_func); @@ -198,7 +287,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } - return mp_obj_new_str(buf, strlen(buf), false); + return mp_obj_new_str(buf, strlen(buf)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); @@ -292,10 +381,8 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs self->writeblocks[0] = MP_OBJ_NULL; } - // mount the block device - FRESULT res = f_mount(&self->fatfs); - // check if we need to make the filesystem + FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) { uint8_t working_buf[_MAX_SS]; res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); @@ -303,17 +390,15 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } + self->flags &= ~FSUSER_NO_FILESYSTEM; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_fat_mount_obj, vfs_fat_mount); STATIC mp_obj_t vfs_fat_umount(mp_obj_t self_in) { - fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); - FRESULT res = f_umount(&self->fatfs); - if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); - } + (void)self_in; + // keep the FAT filesystem mounted internally so the VFS methods can still be used return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount); @@ -352,6 +437,9 @@ STATIC const mp_obj_property_t fat_vfs_label_obj = { #endif STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { + #if _FS_REENTRANT + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&fat_vfs_del_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) }, { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&fat_vfs_ilistdir_obj) }, @@ -371,11 +459,17 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { }; STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); +STATIC const mp_vfs_proto_t fat_vfs_proto = { + .import_stat = fat_vfs_import_stat, +}; + const mp_obj_type_t mp_fat_vfs_type = { { &mp_type_type }, .name = MP_QSTR_VfsFat, .make_new = fat_vfs_make_new, + .protocol = &fat_vfs_proto, .locals_dict = (mp_obj_dict_t*)&fat_vfs_locals_dict, + }; #endif // MICROPY_VFS_FAT diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index be9c8c7921..86ae65aefb 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -94,22 +94,9 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz } -STATIC mp_obj_t file_obj_close(mp_obj_t self_in) { - pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); - // if fs==NULL then the file is closed and in that case this method is a no-op - if (self->fp.obj.fs != NULL) { - FRESULT res = f_close(&self->fp); - if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); - } - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close); - STATIC mp_obj_t file_obj___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - return file_obj_close(args[0]); + return mp_stream_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file_obj___exit___obj, 4, 4, file_obj___exit__); @@ -144,6 +131,17 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, } return 0; + } else if (request == MP_STREAM_CLOSE) { + // if fs==NULL then the file is closed and in that case this method is a no-op + if (self->fp.obj.fs != NULL) { + FRESULT res = f_close(&self->fp); + if (res != FR_OK) { + *errcode = fresult_to_errno_table[res]; + return MP_STREAM_ERROR; + } + } + return 0; + } else { *errcode = MP_EINVAL; return MP_STREAM_ERROR; @@ -182,11 +180,11 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar break; #if MICROPY_PY_IO_FILEIO case 'b': - type = &mp_type_fileio; + type = &mp_type_vfs_fat_fileio; break; #endif case 't': - type = &mp_type_textio; + type = &mp_type_vfs_fat_textio; break; } } @@ -225,10 +223,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&file_obj_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&file_obj_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) }, }; @@ -242,7 +240,7 @@ STATIC const mp_stream_p_t fileio_stream_p = { .ioctl = file_obj_ioctl, }; -const mp_obj_type_t mp_type_fileio = { +const mp_obj_type_t mp_type_vfs_fat_fileio = { { &mp_type_type }, .name = MP_QSTR_FileIO, .print = file_obj_print, @@ -261,7 +259,7 @@ STATIC const mp_stream_p_t textio_stream_p = { .is_text = true, }; -const mp_obj_type_t mp_type_textio = { +const mp_obj_type_t mp_type_vfs_fat_textio = { { &mp_type_type }, .name = MP_QSTR_TextIOWrapper, .print = file_obj_print, @@ -273,14 +271,15 @@ const mp_obj_type_t mp_type_textio = { }; // Factory function for I/O stream classes -mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) { +STATIC mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) { // TODO: analyze buffering args and instantiate appropriate type fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; arg_vals[0].u_obj = path; arg_vals[1].u_obj = mode; arg_vals[2].u_obj = mp_const_none; - return file_open(self, &mp_type_textio, arg_vals); + return file_open(self, &mp_type_vfs_fat_textio, arg_vals); } +MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); #endif // MICROPY_VFS && MICROPY_VFS_FAT diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c deleted file mode 100644 index 9a26b4a2f9..0000000000 --- a/extmod/vfs_fat_misc.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2014 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/mpconfig.h" -#if MICROPY_VFS_FAT - -#include -#include "py/runtime.h" -#include "lib/oofatfs/ff.h" -#include "extmod/vfs_fat.h" -#include "py/lexer.h" - -typedef struct _mp_vfs_fat_ilistdir_it_t { - mp_obj_base_t base; - mp_fun_1_t iternext; - bool is_str; - FF_DIR dir; -} mp_vfs_fat_ilistdir_it_t; - -STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { - mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); - - for (;;) { - FILINFO fno; - FRESULT res = f_readdir(&self->dir, &fno); - char *fn = fno.fname; - if (res != FR_OK || fn[0] == 0) { - // stop on error or end of dir - break; - } - - // Note that FatFS already filters . and .., so we don't need to - - // make 3-tuple with info about this entry - mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); - if (self->is_str) { - t->items[0] = mp_obj_new_str(fn, strlen(fn), false); - } else { - t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); - } - if (fno.fattrib & AM_DIR) { - // dir - t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); - } else { - // file - t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); - } - t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number - - return MP_OBJ_FROM_PTR(t); - } - - // ignore error because we may be closing a second time - f_closedir(&self->dir); - - return MP_OBJ_STOP_ITERATION; -} - -mp_obj_t fat_vfs_ilistdir2(fs_user_mount_t *vfs, const char *path, bool is_str_type) { - mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t); - iter->base.type = &mp_type_polymorph_iter; - iter->iternext = mp_vfs_fat_ilistdir_it_iternext; - iter->is_str = is_str_type; - FRESULT res = f_opendir(&vfs->fatfs, &iter->dir, path); - if (res != FR_OK) { - mp_raise_OSError(fresult_to_errno_table[res]); - } - return MP_OBJ_FROM_PTR(iter); -} - -mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) { - FILINFO fno; - assert(vfs != NULL); - FRESULT res = f_stat(&vfs->fatfs, path, &fno); - if (res == FR_OK) { - if ((fno.fattrib & AM_DIR) != 0) { - return MP_IMPORT_STAT_DIR; - } else { - return MP_IMPORT_STAT_FILE; - } - } - return MP_IMPORT_STAT_NO_EXIST; -} - -#endif // MICROPY_VFS_FAT diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c new file mode 100644 index 0000000000..6e3bb2c5bd --- /dev/null +++ b/extmod/vfs_posix.c @@ -0,0 +1,363 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" +#include "extmod/vfs_posix.h" + +#if MICROPY_VFS_POSIX + +#include +#include +#include + +typedef struct _mp_obj_vfs_posix_t { + mp_obj_base_t base; + vstr_t root; + size_t root_len; + bool readonly; +} mp_obj_vfs_posix_t; + +STATIC const char *vfs_posix_get_path_str(mp_obj_vfs_posix_t *self, mp_obj_t path) { + if (self->root_len == 0) { + return mp_obj_str_get_str(path); + } else { + self->root.len = self->root_len; + vstr_add_str(&self->root, mp_obj_str_get_str(path)); + return vstr_null_terminated_str(&self->root); + } +} + +STATIC mp_obj_t vfs_posix_get_path_obj(mp_obj_vfs_posix_t *self, mp_obj_t path) { + if (self->root_len == 0) { + return path; + } else { + self->root.len = self->root_len; + vstr_add_str(&self->root, mp_obj_str_get_str(path)); + return mp_obj_new_str(self->root.buf, self->root.len); + } +} + +STATIC mp_obj_t vfs_posix_fun1_helper(mp_obj_t self_in, mp_obj_t path_in, int (*f)(const char*)) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + int ret = f(vfs_posix_get_path_str(self, path_in)); + if (ret != 0) { + mp_raise_OSError(errno); + } + return mp_const_none; +} + +STATIC mp_import_stat_t mp_vfs_posix_import_stat(void *self_in, const char *path) { + mp_obj_vfs_posix_t *self = self_in; + if (self->root_len != 0) { + self->root.len = self->root_len; + vstr_add_str(&self->root, path); + path = vstr_null_terminated_str(&self->root); + } + struct stat st; + if (stat(path, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + return MP_IMPORT_STAT_DIR; + } else if (S_ISREG(st.st_mode)) { + return MP_IMPORT_STAT_FILE; + } + } + return MP_IMPORT_STAT_NO_EXIST; +} + +STATIC mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + mp_obj_vfs_posix_t *vfs = m_new_obj(mp_obj_vfs_posix_t); + vfs->base.type = type; + vstr_init(&vfs->root, 0); + if (n_args == 1) { + vstr_add_str(&vfs->root, mp_obj_str_get_str(args[0])); + vstr_add_char(&vfs->root, '/'); + } + vfs->root_len = vfs->root.len; + vfs->readonly = false; + + return MP_OBJ_FROM_PTR(vfs); +} + +STATIC mp_obj_t vfs_posix_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + if (mp_obj_is_true(readonly)) { + self->readonly = true; + } + if (mp_obj_is_true(mkfs)) { + mp_raise_OSError(MP_EPERM); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_mount_obj, vfs_posix_mount); + +STATIC mp_obj_t vfs_posix_umount(mp_obj_t self_in) { + (void)self_in; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount); + +STATIC mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + const char *mode = mp_obj_str_get_str(mode_in); + if (self->readonly + && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) { + mp_raise_OSError(MP_EROFS); + } + if (!MP_OBJ_IS_SMALL_INT(path_in)) { + path_in = vfs_posix_get_path_obj(self, path_in); + } + return mp_vfs_posix_file_open(&mp_type_textio, path_in, mode_in); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_open_obj, vfs_posix_open); + +STATIC mp_obj_t vfs_posix_chdir(mp_obj_t self_in, mp_obj_t path_in) { + return vfs_posix_fun1_helper(self_in, path_in, chdir); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_chdir_obj, vfs_posix_chdir); + +STATIC mp_obj_t vfs_posix_getcwd(mp_obj_t self_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + char buf[MICROPY_ALLOC_PATH_MAX + 1]; + const char *ret = getcwd(buf, sizeof(buf)); + if (ret == NULL) { + mp_raise_OSError(errno); + } + ret += self->root_len; + return mp_obj_new_str(ret, strlen(ret)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_getcwd_obj, vfs_posix_getcwd); + +typedef struct _vfs_posix_ilistdir_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + bool is_str; + DIR *dir; +} vfs_posix_ilistdir_it_t; + +STATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) { + vfs_posix_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->dir == NULL) { + return MP_OBJ_STOP_ITERATION; + } + + for (;;) { + struct dirent *dirent = readdir(self->dir); + if (dirent == NULL) { + closedir(self->dir); + self->dir = NULL; + return MP_OBJ_STOP_ITERATION; + } + const char *fn = dirent->d_name; + + if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) { + // skip . and .. + continue; + } + + // make 3-tuple with info about this entry + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + + if (self->is_str) { + t->items[0] = mp_obj_new_str(fn, strlen(fn)); + } else { + t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); + } + + #ifdef _DIRENT_HAVE_D_TYPE + if (dirent->d_type == DT_DIR) { + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR); + } else if (dirent->d_type == DT_REG) { + t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); + } else { + t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type); + } + #else + // DT_UNKNOWN should have 0 value on any reasonable system + t->items[1] = MP_OBJ_NEW_SMALL_INT(0); + #endif + #ifdef _DIRENT_HAVE_D_INO + t->items[2] = MP_OBJ_NEW_SMALL_INT(dirent->d_ino); + #else + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); + #endif + + return MP_OBJ_FROM_PTR(t); + } +} + +STATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + vfs_posix_ilistdir_it_t *iter = m_new_obj(vfs_posix_ilistdir_it_t); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = vfs_posix_ilistdir_it_iternext; + iter->is_str = mp_obj_get_type(path_in) == &mp_type_str; + const char *path = vfs_posix_get_path_str(self, path_in); + iter->dir = opendir(path); + if (iter->dir == NULL) { + mp_raise_OSError(errno); + } + return MP_OBJ_FROM_PTR(iter); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_ilistdir_obj, vfs_posix_ilistdir); + +typedef struct _mp_obj_listdir_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + DIR *dir; +} mp_obj_listdir_t; + +STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + int ret = mkdir(vfs_posix_get_path_str(self, path_in), 0777); + if (ret != 0) { + mp_raise_OSError(errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir); + +STATIC mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) { + return vfs_posix_fun1_helper(self_in, path_in, unlink); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove); + +STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + const char *old_path = vfs_posix_get_path_str(self, old_path_in); + const char *new_path = vfs_posix_get_path_str(self, new_path_in); + int ret = rename(old_path, new_path); + if (ret != 0) { + mp_raise_OSError(errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename); + +STATIC mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) { + return vfs_posix_fun1_helper(self_in, path_in, rmdir); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir); + +STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + struct stat sb; + int ret = stat(vfs_posix_get_path_str(self, path_in), &sb); + if (ret != 0) { + mp_raise_OSError(errno); + } + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode); + t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino); + t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev); + t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink); + t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid); + t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid); + t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size); + t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime); + t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime); + t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat); + +#ifdef __ANDROID__ +#define USE_STATFS 1 +#endif + +#if USE_STATFS +#include +#define STRUCT_STATVFS struct statfs +#define STATVFS statfs +#define F_FAVAIL sb.f_ffree +#define F_NAMEMAX sb.f_namelen +#define F_FLAG sb.f_flags +#else +#include +#define STRUCT_STATVFS struct statvfs +#define STATVFS statvfs +#define F_FAVAIL sb.f_favail +#define F_NAMEMAX sb.f_namemax +#define F_FLAG sb.f_flag +#endif + +STATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + STRUCT_STATVFS sb; + const char *path = vfs_posix_get_path_str(self, path_in); + int ret = STATVFS(path, &sb); + if (ret != 0) { + mp_raise_OSError(errno); + } + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize); + t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize); + t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.f_blocks); + t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.f_bfree); + t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.f_bavail); + t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.f_files); + t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.f_ffree); + t->items[7] = MP_OBJ_NEW_SMALL_INT(F_FAVAIL); + t->items[8] = MP_OBJ_NEW_SMALL_INT(F_FLAG); + t->items[9] = MP_OBJ_NEW_SMALL_INT(F_NAMEMAX); + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_statvfs_obj, vfs_posix_statvfs); + +STATIC const mp_rom_map_elem_t vfs_posix_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_posix_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&vfs_posix_umount_obj) }, + { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&vfs_posix_open_obj) }, + + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&vfs_posix_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&vfs_posix_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&vfs_posix_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&vfs_posix_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&vfs_posix_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&vfs_posix_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&vfs_posix_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&vfs_posix_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&vfs_posix_statvfs_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(vfs_posix_locals_dict, vfs_posix_locals_dict_table); + +STATIC const mp_vfs_proto_t vfs_posix_proto = { + .import_stat = mp_vfs_posix_import_stat, +}; + +const mp_obj_type_t mp_type_vfs_posix = { + { &mp_type_type }, + .name = MP_QSTR_VfsPosix, + .make_new = vfs_posix_make_new, + .protocol = &vfs_posix_proto, + .locals_dict = (mp_obj_dict_t*)&vfs_posix_locals_dict, +}; + +#endif // MICROPY_VFS_POSIX diff --git a/extmod/vfs_posix.h b/extmod/vfs_posix.h new file mode 100644 index 0000000000..00756b4c9d --- /dev/null +++ b/extmod/vfs_posix.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H +#define MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H + +#include "py/lexer.h" +#include "py/obj.h" + +extern const mp_obj_type_t mp_type_vfs_posix; +extern const mp_obj_type_t mp_type_vfs_posix_fileio; +extern const mp_obj_type_t mp_type_vfs_posix_textio; + +mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in); + +#endif // MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c new file mode 100644 index 0000000000..435ac65cd4 --- /dev/null +++ b/extmod/vfs_posix_file.c @@ -0,0 +1,261 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/stream.h" +#include "extmod/vfs_posix.h" + +#if MICROPY_VFS_POSIX + +#include + +#ifdef _WIN32 +#define fsync _commit +#endif + +typedef struct _mp_obj_vfs_posix_file_t { + mp_obj_base_t base; + int fd; +} mp_obj_vfs_posix_file_t; + +#ifdef MICROPY_CPYTHON_COMPAT +STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) { + if (o->fd < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file")); + } +} +#else +#define check_fd_is_open(o) +#endif + +STATIC void vfs_posix_file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", mp_obj_get_type_str(self_in), self->fd); +} + +mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in) { + mp_obj_vfs_posix_file_t *o = m_new_obj(mp_obj_vfs_posix_file_t); + const char *mode_s = mp_obj_str_get_str(mode_in); + + int mode_rw = 0, mode_x = 0; + while (*mode_s) { + switch (*mode_s++) { + case 'r': + mode_rw = O_RDONLY; + break; + case 'w': + mode_rw = O_WRONLY; + mode_x = O_CREAT | O_TRUNC; + break; + case 'a': + mode_rw = O_WRONLY; + mode_x = O_CREAT | O_APPEND; + break; + case '+': + mode_rw = O_RDWR; + break; + #if MICROPY_PY_IO_FILEIO + // If we don't have io.FileIO, then files are in text mode implicitly + case 'b': + type = &mp_type_vfs_posix_fileio; + break; + case 't': + type = &mp_type_vfs_posix_textio; + break; + #endif + } + } + + o->base.type = type; + + mp_obj_t fid = file_in; + + if (MP_OBJ_IS_SMALL_INT(fid)) { + o->fd = MP_OBJ_SMALL_INT_VALUE(fid); + return MP_OBJ_FROM_PTR(o); + } + + const char *fname = mp_obj_str_get_str(fid); + int fd = open(fname, mode_x | mode_rw, 0644); + if (fd == -1) { + mp_raise_OSError(errno); + } + o->fd = fd; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, + }; + + mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); + return mp_vfs_posix_file_open(type, arg_vals[0].u_obj, arg_vals[1].u_obj); +} + +STATIC mp_obj_t vfs_posix_file_fileno(mp_obj_t self_in) { + mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in); + check_fd_is_open(self); + return MP_OBJ_NEW_SMALL_INT(self->fd); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_file_fileno_obj, vfs_posix_file_fileno); + +STATIC mp_obj_t vfs_posix_file___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return mp_stream_close(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vfs_posix_file___exit__); + +STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + mp_int_t r = read(o->fd, buf, size); + if (r == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + #if MICROPY_PY_OS_DUPTERM + if (o->fd <= STDERR_FILENO) { + mp_hal_stdout_tx_strn(buf, size); + return size; + } + #endif + mp_int_t r = write(o->fd, buf, size); + while (r == -1 && errno == EINTR) { + if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } + r = write(o->fd, buf, size); + } + if (r == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return r; +} + +STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); + check_fd_is_open(o); + switch (request) { + case MP_STREAM_FLUSH: + if (fsync(o->fd) < 0) { + *errcode = errno; + return MP_STREAM_ERROR; + } + return 0; + case MP_STREAM_SEEK: { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg; + off_t off = lseek(o->fd, s->offset, s->whence); + if (off == (off_t)-1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + s->offset = off; + return 0; + } + case MP_STREAM_CLOSE: + close(o->fd); + #ifdef MICROPY_CPYTHON_COMPAT + o->fd = -1; + #endif + return 0; + default: + *errcode = EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_posix_file_fileno_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, + { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); + +#if MICROPY_PY_IO_FILEIO +STATIC const mp_stream_p_t fileio_stream_p = { + .read = vfs_posix_file_read, + .write = vfs_posix_file_write, + .ioctl = vfs_posix_file_ioctl, +}; + +const mp_obj_type_t mp_type_vfs_posix_fileio = { + { &mp_type_type }, + .name = MP_QSTR_FileIO, + .print = vfs_posix_file_print, + .make_new = vfs_posix_file_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &fileio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; +#endif + +STATIC const mp_stream_p_t textio_stream_p = { + .read = vfs_posix_file_read, + .write = vfs_posix_file_write, + .ioctl = vfs_posix_file_ioctl, + .is_text = true, +}; + +const mp_obj_type_t mp_type_vfs_posix_textio = { + { &mp_type_type }, + .name = MP_QSTR_TextIOWrapper, + .print = vfs_posix_file_print, + .make_new = vfs_posix_file_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &textio_stream_p, + .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict, +}; + +const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO}; + +#endif // MICROPY_VFS_POSIX diff --git a/extmod/vfs_reader.c b/extmod/vfs_reader.c index 891098aa1e..e1ee45a3c7 100644 --- a/extmod/vfs_reader.c +++ b/extmod/vfs_reader.c @@ -71,7 +71,7 @@ STATIC void mp_reader_vfs_close(void *data) { void mp_reader_new_file(mp_reader_t *reader, const char *filename) { mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t); - mp_obj_t arg = mp_obj_new_str(filename, strlen(filename), false); + mp_obj_t arg = mp_obj_new_str(filename, strlen(filename)); rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map); int errcode; rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); diff --git a/lib/netutils/netutils.c b/lib/netutils/netutils.c index 06c3ff9b08..073f46b199 100644 --- a/lib/netutils/netutils.c +++ b/lib/netutils/netutils.c @@ -41,7 +41,7 @@ mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian) { } else { ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); } - return mp_obj_new_str(ip_str, ip_len, false); + return mp_obj_new_str(ip_str, ip_len); } // Takes an array with a raw IP address, and a port, and returns a net-address diff --git a/tools/tinytest/README b/lib/tinytest/README similarity index 100% rename from tools/tinytest/README rename to lib/tinytest/README diff --git a/tools/tinytest/tinytest.c b/lib/tinytest/tinytest.c similarity index 98% rename from tools/tinytest/tinytest.c rename to lib/tinytest/tinytest.c index 1ef957d31b..01772f3f8e 100644 --- a/tools/tinytest/tinytest.c +++ b/lib/tinytest/tinytest.c @@ -234,8 +234,9 @@ testcase_run_one(const struct testgroup_t *group, return SKIP; } + printf("# starting %s%s\n", group->prefix, testcase->name); if (opt_verbosity>0 && !opt_forked) { - printf("%s%s: ", group->prefix, testcase->name); + //printf("%s%s: ", group->prefix, testcase->name); } else { if (opt_verbosity==0) printf("."); cur_test_prefix = group->prefix; @@ -252,6 +253,7 @@ testcase_run_one(const struct testgroup_t *group, outcome = testcase_run_bare_(testcase); } + printf("%s%s: ", group->prefix, testcase->name); if (outcome == OK) { ++n_ok; if (opt_verbosity>0 && !opt_forked) @@ -263,7 +265,8 @@ testcase_run_one(const struct testgroup_t *group, } else { ++n_bad; if (!opt_forked) - printf("\n [%s FAILED]\n", testcase->name); + //printf("\n [%s FAILED]\n", testcase->name); + puts("FAILED"); } if (opt_forked) { diff --git a/tools/tinytest/tinytest.h b/lib/tinytest/tinytest.h similarity index 100% rename from tools/tinytest/tinytest.h rename to lib/tinytest/tinytest.h diff --git a/tools/tinytest/tinytest_macros.h b/lib/tinytest/tinytest_macros.h similarity index 100% rename from tools/tinytest/tinytest_macros.h rename to lib/tinytest/tinytest_macros.h diff --git a/lib/upytesthelper/upytesthelper.c b/lib/upytesthelper/upytesthelper.c new file mode 100644 index 0000000000..d28c5b9cc0 --- /dev/null +++ b/lib/upytesthelper/upytesthelper.c @@ -0,0 +1,126 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "py/mphal.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "py/compile.h" +#include "upytesthelper.h" + +static const char *test_exp_output; +static int test_exp_output_len, test_rem_output_len; +static int test_failed; +static void *heap_start, *heap_end; + +void upytest_set_heap(void *start, void *end) { + heap_start = start; + heap_end = end; +} + +void upytest_set_expected_output(const char *output, unsigned len) { + test_exp_output = output; + test_exp_output_len = test_rem_output_len = len; + test_failed = false; +} + +bool upytest_is_failed(void) { + if (test_failed) { + return true; + } + #if 0 + if (test_rem_output_len != 0) { + printf("remaining len: %d\n", test_rem_output_len); + } + #endif + return test_rem_output_len != 0; +} + +// MP_PLAT_PRINT_STRN() should be redirected to this function. +// It will pass-thru any content to mp_hal_stdout_tx_strn_cooked() +// (the dfault value of MP_PLAT_PRINT_STRN), but will also match +// it to the expected output as set by upytest_set_expected_output(). +// If mismatch happens, upytest_is_failed() returns true. +void upytest_output(const char *str, mp_uint_t len) { + if (!test_failed) { + if (len > test_rem_output_len) { + test_failed = true; + } else { + test_failed = memcmp(test_exp_output, str, len); + #if 0 + if (test_failed) { + printf("failed after char %u, within %d chars, res: %d\n", + test_exp_output_len - test_rem_output_len, (int)len, test_failed); + for (int i = 0; i < len; i++) { + if (str[i] != test_exp_output[i]) { + printf("%d %02x %02x\n", i, str[i], test_exp_output[i]); + } + } + } + #endif + test_exp_output += len; + test_rem_output_len -= len; + } + } + mp_hal_stdout_tx_strn_cooked(str, len); +} + +void upytest_execute_test(const char *src) { + // To provide clean room for each test, interpreter and heap are + // reinitialized before running each. + gc_init(heap_start, heap_end); + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_init(mp_sys_argv, 0); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + mp_obj_t exc = (mp_obj_t)nlr.ret_val; + if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { + // Assume that sys.exit() is called to skip the test. + // TODO: That can be always true, we should set up convention to + // use specific exit code as skip indicator. + tinytest_set_test_skipped_(); + goto end; + } + mp_obj_print_exception(&mp_plat_print, exc); + tt_abort_msg("Uncaught exception\n"); + } + + if (upytest_is_failed()) { + tinytest_set_test_failed_(); + } + +end: + mp_deinit(); +} diff --git a/lib/upytesthelper/upytesthelper.h b/lib/upytesthelper/upytesthelper.h new file mode 100644 index 0000000000..3a292befd7 --- /dev/null +++ b/lib/upytesthelper/upytesthelper.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "py/mpconfig.h" +#include "lib/tinytest/tinytest.h" +#include "lib/tinytest/tinytest_macros.h" + +void upytest_set_heap(void *start, void *end); +void upytest_set_expected_output(const char *output, unsigned len); +void upytest_execute_test(const char *src); +void upytest_output(const char *str, mp_uint_t len); +bool upytest_is_failed(void); diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 929ee5224d..8cd9848cae 100755 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -36,7 +36,7 @@ #include "py/gc_long_lived.h" #include "py/frozenmod.h" #include "py/mphal.h" -#if defined(USE_DEVICE_MODE) +#if MICROPY_HW_ENABLE_USB #include "irq.h" #include "usb.h" #endif @@ -431,7 +431,7 @@ friendly_repl_reset: for (;;) { input_restart: - #if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB if (usb_vcp_is_enabled()) { // If the user gets to here and interrupts are disabled then // they'll never see the prompt, traceback etc. The USB REPL needs diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index d3411f06af..bde516c593 100644 --- a/lib/utils/pyexec.h +++ b/lib/utils/pyexec.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H #define MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H +#include "py/obj.h" + typedef enum { PYEXEC_MODE_RAW_REPL, PYEXEC_MODE_FRIENDLY_REPL, diff --git a/ports/bare-arm/Makefile b/ports/bare-arm/Makefile index 0fcd5d0272..a515db80e0 100644 --- a/ports/bare-arm/Makefile +++ b/ports/bare-arm/Makefile @@ -36,7 +36,7 @@ SRC_S = \ # startup_stm32f40xx.s \ gchelper.s \ -OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o)) +OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o)) all: $(BUILD)/firmware.elf diff --git a/ports/cc3200/mods/modusocket.c b/ports/cc3200/mods/modusocket.c index f587e765ae..286b1fb02b 100644 --- a/ports/cc3200/mods/modusocket.c +++ b/ports/cc3200/mods/modusocket.c @@ -336,6 +336,9 @@ STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp if (SL_FD_ISSET(sd, &xfds)) { ret |= MP_STREAM_POLL_HUP; } + } else if (request == MP_STREAM_CLOSE) { + wlan_socket_close(s); + ret = 0; } else { *_errno = MP_EINVAL; ret = MP_STREAM_ERROR; @@ -466,14 +469,6 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t return s; } -// method socket.close() -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mod_network_socket_obj_t *self = self_in; - wlan_socket_close(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); - // method socket.bind(address) STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { mod_network_socket_obj_t *self = self_in; @@ -704,8 +699,8 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile); STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, diff --git a/ports/cc3200/mods/modusocket.h b/ports/cc3200/mods/modusocket.h index 6e7758662e..aaee04ce19 100644 --- a/ports/cc3200/mods/modusocket.h +++ b/ports/cc3200/mods/modusocket.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H #define MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H +#include "py/stream.h" + extern const mp_obj_dict_t socket_locals_dict; extern const mp_stream_p_t socket_stream_p; diff --git a/ports/cc3200/mods/modwlan.c b/ports/cc3200/mods/modwlan.c index 005334a796..c27e993bc0 100644 --- a/ports/cc3200/mods/modwlan.c +++ b/ports/cc3200/mods/modwlan.c @@ -886,7 +886,7 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) { } mp_obj_t tuple[5]; - tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len, false); + tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len); tuple[1] = mp_obj_new_bytes((const byte *)wlanEntry.bssid, SL_BSSID_LENGTH); // 'normalize' the security type if (wlanEntry.sec_type > 2) { @@ -1076,7 +1076,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_mode_obj, 1, 2, wlan_mode); STATIC mp_obj_t wlan_ssid(size_t n_args, const mp_obj_t *args) { wlan_obj_t *self = args[0]; if (n_args == 1) { - return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid), false); + return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid)); } else { size_t len; const char *ssid = mp_obj_str_get_data(args[1], &len); @@ -1096,7 +1096,7 @@ STATIC mp_obj_t wlan_auth(size_t n_args, const mp_obj_t *args) { } else { mp_obj_t security[2]; security[0] = mp_obj_new_int(self->auth); - security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key), false); + security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key)); return mp_obj_new_tuple(2, security); } } else { @@ -1200,7 +1200,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); // mp_obj_t connections = mp_obj_new_list(0, NULL); // // if (wlan_is_connected()) { -// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o), false); +// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o)); // device[1] = mp_obj_new_bytes((const byte *)wlan_obj.bssid, SL_BSSID_LENGTH); // // add the device to the list // mp_obj_list_append(connections, mp_obj_new_tuple(MP_ARRAY_SIZE(device), device)); @@ -1233,7 +1233,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); // if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) { // mp_raise_OSError(MP_EIO); // } -// return mp_obj_new_str(urn, (len - 1), false); +// return mp_obj_new_str(urn, (len - 1)); // } // // return mp_const_none; diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h index 29ae9092b1..ee9a226e5c 100644 --- a/ports/cc3200/mpconfigport.h +++ b/ports/cc3200/mpconfigport.h @@ -131,8 +131,8 @@ X(ETIMEDOUT) \ // TODO these should be generic, not bound to fatfs -#define mp_type_fileio fatfs_type_fileio -#define mp_type_textio fatfs_type_textio +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio // use vfs's functions for import stat and builtin open #define mp_import_stat mp_vfs_import_stat diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile new file mode 100644 index 0000000000..b0baa0dca1 --- /dev/null +++ b/ports/esp32/Makefile @@ -0,0 +1,786 @@ +include ../../py/mkenv.mk + +# qstr definitions (must come before including py.mk) +QSTR_DEFS = qstrdefsport.h + +MICROPY_PY_USSL = 0 +MICROPY_SSL_AXTLS = 0 +MICROPY_FATFS = 1 +MICROPY_PY_BTREE = 1 + +#FROZEN_DIR = scripts +FROZEN_MPY_DIR = modules + +# include py core make definitions +include $(TOP)/py/py.mk + +PORT ?= /dev/ttyUSB0 +BAUD ?= 460800 +FLASH_MODE ?= dio +FLASH_FREQ ?= 40m +FLASH_SIZE ?= 4MB +CROSS_COMPILE ?= xtensa-esp32-elf- + +ESPIDF_SUPHASH := 9a55b42f0841b3d38a61089b1dda4bf28135decd + +# paths to ESP IDF and its components +ifeq ($(ESPIDF),) +ifneq ($(IDF_PATH),) +ESPIDF = $(IDF_PATH) +else +$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.) +$(info See README.md for installation instructions.) +$(info Supported git hash: $(ESPIDF_SUPHASH)) +$(error ESPIDF not set) +endif +endif +ESPCOMP = $(ESPIDF)/components +ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py + +# verify the ESP IDF version +ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') +ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH)) +$(info ** WARNING **) +$(info The git hash of ESP IDF does not match the supported version) +$(info The build may complete and the firmware may work but it is not guaranteed) +$(info ESP IDF path: $(ESPIDF)) +$(info Current git hash: $(ESPIDF_CURHASH)) +$(info Supported git hash: $(ESPIDF_SUPHASH)) +endif + +# pretty format of ESP IDF version, used internally by the IDF +IDF_VER := $(shell git -C $(ESPIDF) describe) + +INC += -I. +INC += -I$(TOP) +INC += -I$(TOP)/lib/mp-readline +INC += -I$(TOP)/lib/netutils +INC += -I$(TOP)/lib/timeutils +INC += -I$(BUILD) + +INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include +INC_ESPCOMP += -I$(ESPCOMP)/driver/include +INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include +INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes +INC_ESPCOMP += -I$(ESPCOMP)/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/include +INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include +INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include +INC_ESPCOMP += -I$(ESPCOMP)/expat/include/expat +INC_ESPCOMP += -I$(ESPCOMP)/expat/port/include +INC_ESPCOMP += -I$(ESPCOMP)/heap/include +INC_ESPCOMP += -I$(ESPCOMP)/json/include +INC_ESPCOMP += -I$(ESPCOMP)/json/port/include +INC_ESPCOMP += -I$(ESPCOMP)/log/include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/include +INC_ESPCOMP += -I$(ESPCOMP)/nvs_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/freertos/include +INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/port +INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/posix +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include +INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include +INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include +INC_ESPCOMP += -I$(ESPCOMP)/ulp/include +INC_ESPCOMP += -I$(ESPCOMP)/vfs/include +INC_ESPCOMP += -I$(ESPCOMP)/newlib/platform_include +INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include +INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include +INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include +INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include +INC_ESPCOMP += -I$(ESPCOMP)/app_update/include +INC_ESPCOMP += -I$(ESPCOMP)/pthread/include +INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include + +# these flags are common to C and C++ compilation +CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ + -mlongcalls -nostdlib \ + -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable \ + -Wno-error=unused-variable -Wno-error=deprecated-declarations \ + -DESP_PLATFORM + +CFLAGS_BASE = -std=gnu99 $(CFLAGS_COMMON) -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H +CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP) +CFLAGS += -DIDF_VER=\"$(IDF_VER)\" +CFLAGS += $(CFLAGS_MOD) + +# this is what ESPIDF uses for c++ compilation +CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP) + +LDFLAGS = -nostdlib -Map=$(@:.elf=.map) --cref +LDFLAGS += --gc-sections -static -EL +LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_highint_hdl +LDFLAGS += -u __cxa_guard_dummy # so that implementation of static guards is taken from cxx_guards.o instead of libstdc++.a +LDFLAGS += -L$(ESPCOMP)/esp32/ld +LDFLAGS += -T $(BUILD)/esp32_out.ld +LDFLAGS += -T ./esp32.custom_common.ld +LDFLAGS += -T esp32.rom.ld +LDFLAGS += -T esp32.peripherals.ld + +LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) +LIBSTDCXX_FILE_NAME = $(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a) + +# Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -g +COPT = -O0 +else +#CFLAGS += -fdata-sections -ffunction-sections +COPT += -Os -DNDEBUG +#LDFLAGS += --gc-sections +endif + +# Enable SPIRAM support if CONFIG_SPIRAM_SUPPORT=1 +ifeq ($(CONFIG_SPIRAM_SUPPORT),1) +CFLAGS_COMMON += -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_SUPPORT=1 +LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc-psram-workaround.a $(ESPCOMP)/newlib/lib/libm-psram-workaround.a +else +LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld +LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc.a $(ESPCOMP)/newlib/lib/libm.a +endif + +################################################################################ +# List of MicroPython source and object files + +SRC_C = \ + main.c \ + uart.c \ + gccollect.c \ + mphalport.c \ + fatfs_port.c \ + help.c \ + modutime.c \ + moduos.c \ + machine_timer.c \ + machine_pin.c \ + machine_touchpad.c \ + machine_adc.c \ + machine_dac.c \ + machine_pwm.c \ + machine_uart.c \ + modmachine.c \ + modnetwork.c \ + network_lan.c \ + modsocket.c \ + modesp.c \ + esp32_ulp.c \ + modesp32.c \ + espneopixel.c \ + machine_hw_spi.c \ + machine_wdt.c \ + mpthreadport.c \ + machine_rtc.c \ + $(SRC_MOD) + +EXTMOD_SRC_C = $(addprefix extmod/,\ + modonewire.c \ + ) + +LIB_SRC_C = $(addprefix lib/,\ + libm/math.c \ + libm/fmodf.c \ + libm/roundf.c \ + libm/ef_sqrt.c \ + libm/kf_rem_pio2.c \ + libm/kf_sin.c \ + libm/kf_cos.c \ + libm/kf_tan.c \ + libm/ef_rem_pio2.c \ + libm/sf_sin.c \ + libm/sf_cos.c \ + libm/sf_tan.c \ + libm/sf_frexp.c \ + libm/sf_modf.c \ + libm/sf_ldexp.c \ + libm/asinfacosf.c \ + libm/atanf.c \ + libm/atan2f.c \ + mp-readline/readline.c \ + netutils/netutils.c \ + timeutils/timeutils.c \ + utils/pyexec.c \ + utils/interrupt_char.c \ + utils/sys_stdio_mphal.c \ + ) + +ifeq ($(MICROPY_FATFS), 1) +LIB_SRC_C += \ + lib/oofatfs/ff.c \ + lib/oofatfs/option/unicode.c +endif + +DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ + dht/dht.c \ + ) + +OBJ_MP = +OBJ_MP += $(PY_O) +OBJ_MP += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ_MP += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) +OBJ_MP += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) +OBJ_MP += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) + +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C) +# Append any auto-generated sources that are needed by sources listed in SRC_QSTR +SRC_QSTR_AUTO_DEPS += + +################################################################################ +# List of object files from the ESP32 IDF components + +ESPIDF_DRIVER_O = $(addprefix $(ESPCOMP)/driver/,\ + uart.o \ + periph_ctrl.o \ + ledc.o \ + gpio.o \ + timer.o \ + spi_master.o \ + spi_common.o \ + rtc_module.o \ + ) + +$(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds +ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ + brownout.o \ + panic.o \ + esp_timer.o \ + esp_timer_esp32.o \ + ets_timer_legacy.o \ + event_default_handlers.o \ + fast_crypto_ops.o \ + task_wdt.o \ + cache_err_int.o \ + clk.o \ + core_dump.o \ + cpu_start.o \ + gdbstub.o \ + crosscore_int.o \ + ipc.o \ + int_wdt.o \ + event_loop.o \ + hwcrypto/sha.o \ + hwcrypto/aes.o \ + lib_printf.o \ + freertos_hooks.o \ + system_api.o \ + hw_random.o \ + phy_init.o \ + intr_alloc.o \ + dport_access.o \ + wifi_init.o \ + wifi_os_adapter.o \ + sleep_modes.o \ + spiram.o \ + spiram_psram.o \ + ) + +ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\ + heap_caps.o \ + heap_caps_init.o \ + multi_heap.o \ + ) + +ESPIDF_SOC_O = $(addprefix $(ESPCOMP)/soc/,\ + esp32/cpu_util.o \ + esp32/rtc_clk.o \ + esp32/rtc_init.o \ + esp32/rtc_pm.o \ + esp32/rtc_sleep.o \ + esp32/rtc_time.o \ + esp32/soc_memory_layout.o \ + esp32/spi_periph.o \ + ) + +ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\ + cxx_guards.o \ + ) + +ESPIDF_ETHERNET_O = $(addprefix $(ESPCOMP)/ethernet/,\ + emac_dev.o \ + emac_main.o \ + eth_phy/phy_tlk110.o \ + eth_phy/phy_lan8720.o \ + eth_phy/phy_common.o \ + ) + +$(BUILD)/$(ESPCOMP)/expat/%.o: CFLAGS += -Wno-unused-function +ESPIDF_EXPAT_O = $(addprefix $(ESPCOMP)/expat/,\ + library/xmltok_ns.o \ + library/xmltok.o \ + library/xmlparse.o \ + library/xmlrole.o \ + library/xmltok_impl.o \ + port/minicheck.o \ + port/expat_element.o \ + port/chardata.o \ + ) + +ESPIDF_PTHREAD_O = $(addprefix $(ESPCOMP)/pthread/,\ + pthread.o \ + pthread_local_storage.o \ + ) + +# Assembler .S files need only basic flags, and in particular should not have +# -Os because that generates subtly different code. +# We also need custom CFLAGS for .c files because FreeRTOS has headers with +# generic names (eg queue.h) which can clash with other files in the port. +CFLAGS_ASM = -I$(ESPCOMP)/esp32/include -I$(ESPCOMP)/soc/esp32/include -I$(ESPCOMP)/freertos/include/freertos -I. +$(BUILD)/$(ESPCOMP)/freertos/portasm.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/xtensa_context.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/xtensa_intr_asm.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/xtensa_vectors.o: CFLAGS = $(CFLAGS_ASM) +$(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos -D_ESP_FREERTOS_INTERNAL +ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\ + croutine.o \ + event_groups.o \ + FreeRTOS-openocd.o \ + list.o \ + portasm.o \ + port.o \ + queue.o \ + ringbuf.o \ + tasks.o \ + timers.o \ + xtensa_context.o \ + xtensa_init.o \ + xtensa_intr_asm.o \ + xtensa_intr.o \ + xtensa_overlay_os_hook.o \ + xtensa_vector_defaults.o \ + xtensa_vectors.o \ + ) + +ESPIDF_VFS_O = $(addprefix $(ESPCOMP)/vfs/,\ + vfs_uart.o \ + vfs.o \ + ) + +ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/cJSON/,\ + cJSON.o \ + cJSON_Utils.o \ + ) + +ESPIDF_LOG_O = $(addprefix $(ESPCOMP)/log/,\ + log.o \ + ) + +ESPIDF_XTENSA_DEBUG_MODULE_O = $(addprefix $(ESPCOMP)/xtensa-debug-module/,\ + eri.o \ + trax.o \ + ) + +ESPIDF_TCPIP_ADAPTER_O = $(addprefix $(ESPCOMP)/tcpip_adapter/,\ + tcpip_adapter_lwip.o \ + ) + +ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\ + app_trace.o \ + ) + +ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\ + esp_ota_ops.o \ + ) + +ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\ + time.o \ + select.o \ + syscalls.o \ + syscall_table.o \ + reent_init.o \ + locks.o \ + ) + +ESPIDF_NGHTTP_O = $(addprefix $(ESPCOMP)/nghttp/,\ + nghttp2/lib/nghttp2_http.o \ + nghttp2/lib/nghttp2_version.o \ + nghttp2/lib/nghttp2_mem.o \ + nghttp2/lib/nghttp2_hd_huffman.o \ + nghttp2/lib/nghttp2_rcbuf.o \ + nghttp2/lib/nghttp2_callbacks.o \ + nghttp2/lib/nghttp2_session.o \ + nghttp2/lib/nghttp2_stream.o \ + nghttp2/lib/nghttp2_hd.o \ + nghttp2/lib/nghttp2_priority_spec.o \ + nghttp2/lib/nghttp2_buf.o \ + nghttp2/lib/nghttp2_option.o \ + nghttp2/lib/nghttp2_npn.o \ + nghttp2/lib/nghttp2_helper.o \ + nghttp2/lib/nghttp2_frame.o \ + nghttp2/lib/nghttp2_outbound_item.o \ + nghttp2/lib/nghttp2_hd_huffman_data.o \ + nghttp2/lib/nghttp2_pq.o \ + nghttp2/lib/nghttp2_queue.o \ + nghttp2/lib/nghttp2_submit.o \ + nghttp2/lib/nghttp2_map.o \ + port/http_parser.o \ + ) + +ESPIDF_NVS_FLASH_O = $(addprefix $(ESPCOMP)/nvs_flash/,\ + src/nvs_types.o \ + src/nvs_page.o \ + src/nvs_item_hash_list.o \ + src/nvs_pagemanager.o \ + src/nvs_storage.o \ + src/nvs_api.o \ + ) + +ESPIDF_OPENSSL_O = $(addprefix $(ESPCOMP)/openssl/,\ + ) + +ESPIDF_SMARTCONFIG_ACK_O = $(addprefix $(ESPCOMP)/smartconfig_ack/,\ + smartconfig_ack.o \ + ) + +ESPIDF_SPI_FLASH_O = $(addprefix $(ESPCOMP)/spi_flash/,\ + flash_mmap.o \ + partition.o \ + spi_flash_rom_patch.o \ + cache_utils.o \ + flash_ops.o \ + ) + +ESPIDF_ULP_O = $(addprefix $(ESPCOMP)/ulp/,\ + ulp.o \ + ) + +$(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable +ESPIDF_LWIP_O = $(addprefix $(ESPCOMP)/lwip/,\ + api/pppapi.o \ + api/netbuf.o \ + api/api_lib.o \ + api/netifapi.o \ + api/tcpip.o \ + api/netdb.o \ + api/err.o \ + api/api_msg.o \ + api/sockets.o \ + apps/sntp/sntp.o \ + apps/dhcpserver.o \ + core/ipv4/ip_frag.o \ + core/ipv4/dhcp.o \ + core/ipv4/ip4_addr.o \ + core/ipv4/igmp.o \ + core/ipv4/ip4.o \ + core/ipv4/autoip.o \ + core/ipv4/icmp.o \ + core/ipv6/ip6_frag.o \ + core/ipv6/dhcp6.o \ + core/ipv6/inet6.o \ + core/ipv6/ip6_addr.o \ + core/ipv6/ip6.o \ + core/ipv6/nd6.o \ + core/ipv6/mld6.o \ + core/ipv6/ethip6.o \ + core/ipv6/icmp6.o \ + core/mem.o \ + core/init.o \ + core/memp.o \ + core/sys.o \ + core/tcp_in.o \ + core/dns.o \ + core/ip.o \ + core/pbuf.o \ + core/raw.o \ + core/tcp.o \ + core/def.o \ + core/netif.o \ + core/stats.o \ + core/timers.o \ + core/inet_chksum.o \ + core/udp.o \ + core/tcp_out.o \ + netif/slipif.o \ + netif/etharp.o \ + netif/ethernet.o \ + netif/lowpan6.o \ + netif/ethernetif.o \ + port/freertos/sys_arch.o \ + port/netif/wlanif.o \ + port/netif/ethernetif.o \ + port/vfs_lwip.o \ + ) + +ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\ + mbedtls/library/entropy.o \ + mbedtls/library/pkcs12.o \ + mbedtls/library/ccm.o \ + mbedtls/library/pk.o \ + mbedtls/library/sha1.o \ + mbedtls/library/x509_csr.o \ + mbedtls/library/ssl_cli.o \ + mbedtls/library/ecp.o \ + mbedtls/library/blowfish.o \ + mbedtls/library/x509.o \ + mbedtls/library/ecp_curves.o \ + mbedtls/library/error.o \ + mbedtls/library/ssl_ticket.o \ + mbedtls/library/entropy_poll.o \ + mbedtls/library/cipher.o \ + mbedtls/library/version_features.o \ + mbedtls/library/ripemd160.o \ + mbedtls/library/rsa.o \ + mbedtls/library/rsa_internal.o \ + mbedtls/library/md.o \ + mbedtls/library/md_wrap.o \ + mbedtls/library/sha256.o \ + mbedtls/library/dhm.o \ + mbedtls/library/ssl_cache.o \ + mbedtls/library/pkwrite.o \ + mbedtls/library/base64.o \ + mbedtls/library/asn1parse.o \ + mbedtls/library/ssl_tls.o \ + mbedtls/library/hmac_drbg.o \ + mbedtls/library/pem.o \ + mbedtls/library/version.o \ + mbedtls/library/gcm.o \ + mbedtls/library/memory_buffer_alloc.o \ + mbedtls/library/md2.o \ + mbedtls/library/ecdsa.o \ + mbedtls/library/ssl_srv.o \ + mbedtls/library/x509_crt.o \ + mbedtls/library/ecdh.o \ + mbedtls/library/asn1write.o \ + mbedtls/library/md4.o \ + mbedtls/library/debug.o \ + mbedtls/library/x509_create.o \ + mbedtls/library/ecjpake.o \ + mbedtls/library/oid.o \ + mbedtls/library/md5.o \ + mbedtls/library/ssl_ciphersuites.o \ + mbedtls/library/sha512.o \ + mbedtls/library/xtea.o \ + mbedtls/library/aes.o \ + mbedtls/library/cipher_wrap.o \ + mbedtls/library/arc4.o \ + mbedtls/library/bignum.o \ + mbedtls/library/pkparse.o \ + mbedtls/library/padlock.o \ + mbedtls/library/threading.o \ + mbedtls/library/x509_crl.o \ + mbedtls/library/pkcs11.o \ + mbedtls/library/aesni.o \ + mbedtls/library/timing.o \ + mbedtls/library/certs.o \ + mbedtls/library/pkcs5.o \ + mbedtls/library/ssl_cookie.o \ + mbedtls/library/camellia.o \ + mbedtls/library/havege.o \ + mbedtls/library/des.o \ + mbedtls/library/x509write_csr.o \ + mbedtls/library/platform.o \ + mbedtls/library/ctr_drbg.o \ + mbedtls/library/x509write_crt.o \ + mbedtls/library/pk_wrap.o \ + port/esp_bignum.o \ + port/esp_hardware.o \ + port/esp_sha1.o \ + port/esp_sha256.o \ + port/esp_sha512.o \ + ) + +$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -D__ets__ -Wno-strict-aliasing +ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\ + src/crypto/aes-internal-enc.o \ + src/crypto/sha256-internal.o \ + src/crypto/md5-internal.o \ + src/crypto/aes-internal.o \ + src/crypto/sha1.o \ + src/crypto/aes-internal-dec.o \ + src/crypto/aes-unwrap.o \ + src/crypto/crypto_internal-rsa.o \ + src/crypto/dh_groups.o \ + src/crypto/crypto_internal.o \ + src/crypto/aes-wrap.o \ + src/crypto/sha1-internal.o \ + src/crypto/dh_group5.o \ + src/crypto/sha256.o \ + src/crypto/rc4.o \ + src/crypto/md5.o \ + src/crypto/aes-cbc.o \ + src/crypto/sha1-pbkdf2.o \ + src/crypto/bignum.o \ + src/crypto/crypto_internal-modexp.o \ + src/crypto/crypto_internal-cipher.o \ + src/fast_crypto/fast_aes-unwrap.o \ + src/fast_crypto/fast_aes-wrap.o \ + src/fast_crypto/fast_sha256.o \ + src/fast_crypto/fast_sha256-internal.o \ + port/os_xtensa.o \ + ) + +OBJ_ESPIDF = +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ESP32_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_HEAP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SOC_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_CXX_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ETHERNET_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_EXPAT_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_PTHREAD_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_FREERTOS_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_VFS_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_JSON_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LOG_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LWIP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_MBEDTLS_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_XTENSA_DEBUG_MODULE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_TCPIP_ADAPTER_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_TRACE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_UPDATE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SMARTCONFIG_ACK_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ULP_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O)) +################################################################################ +# Main targets + +all: $(BUILD)/firmware.bin + +.PHONY: idf-version deploy erase + +idf-version: + $(ECHO) "ESP IDF supported hash: $(ESPIDF_SUPHASH)" + +$(BUILD)/firmware.bin: $(BUILD)/bootloader.bin $(BUILD)/partitions.bin $(BUILD)/application.bin + $(ECHO) "Create $@" + $(Q)$(PYTHON) makeimg.py $^ $@ + +deploy: $(BUILD)/firmware.bin + $(ECHO) "Writing $^ to the board" + $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) write_flash -z --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) 0x1000 $^ + +erase: + $(ECHO) "Erasing flash" + $(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) erase_flash + +################################################################################ +# Declarations to build the application + +OBJ = $(OBJ_MP) $(OBJ_ESPIDF) + +APP_LD_ARGS = +APP_LD_ARGS += $(LDFLAGS_MOD) +APP_LD_ARGS += --start-group +APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc +APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++ +APP_LD_ARGS += $(LIBC_LIBM) +APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a +APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2 +APP_LD_ARGS += $(OBJ) +APP_LD_ARGS += --end-group + +$(BUILD)/esp32_out.ld: sdkconfig.h + $(Q)$(CC) -I. -C -P -x c -E $(ESPCOMP)/esp32/ld/esp32.ld -o $@ + +$(BUILD)/application.bin: $(BUILD)/application.elf + $(ECHO) "Create $@" + $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< + +$(BUILD)/application.elf: $(OBJ) $(BUILD)/esp32_out.ld + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS) + $(Q)$(SIZE) $@ + +define compile_cxx +$(ECHO) "CXX $<" +$(Q)$(CXX) $(CXXFLAGS) -c -MD -o $@ $< +@# The following fixes the dependency file. +@# See http://make.paulandlesley.org/autodep.html for details. +@# Regex adjusted from the above to play better with Windows paths, etc. +@$(CP) $(@:.o=.d) $(@:.o=.P); \ + $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ + $(RM) -f $(@:.o=.d) +endef + +vpath %.cpp . $(TOP) +$(BUILD)/%.o: %.cpp + $(call compile_cxx) + +################################################################################ +# Declarations to build the bootloader + +$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/esp32 -Wno-error=format +BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + bootloader_support/src/bootloader_clock.o \ + bootloader_support/src/bootloader_common.o \ + bootloader_support/src/bootloader_flash.o \ + bootloader_support/src/bootloader_init.o \ + bootloader_support/src/bootloader_random.o \ + bootloader_support/src/bootloader_sha.o \ + bootloader_support/src/bootloader_utility.o \ + bootloader_support/src/efuse.o \ + bootloader_support/src/flash_qio_mode.o \ + bootloader_support/src/secure_boot_signatures.o \ + bootloader_support/src/secure_boot.o \ + bootloader_support/src/esp_image_format.o \ + bootloader_support/src/flash_encrypt.o \ + bootloader_support/src/flash_partitions.o \ + log/log.o \ + spi_flash/spi_flash_rom_patch.o \ + soc/esp32/rtc_clk.o \ + soc/esp32/rtc_time.o \ + soc/esp32/cpu_util.o \ + micro-ecc/micro-ecc/uECC.o \ + bootloader/subproject/main/bootloader_start.o \ + ) + +BOOTLOADER_LIBS = +BOOTLOADER_LIBS += -Wl,--start-group +BOOTLOADER_LIBS += $(BOOTLOADER_OBJ) +BOOTLOADER_LIBS += -L$(ESPCOMP)/esp32/lib -lrtc +BOOTLOADER_LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc +BOOTLOADER_LIBS += -Wl,--end-group + +BOOTLOADER_LDFLAGS = +BOOTLOADER_LDFLAGS += -nostdlib +BOOTLOADER_LDFLAGS += -L$(ESPIDF)/lib +BOOTLOADER_LDFLAGS += -L$(ESPIDF)/ld +BOOTLOADER_LDFLAGS += -u call_user_start_cpu0 +BOOTLOADER_LDFLAGS += -Wl,--gc-sections +BOOTLOADER_LDFLAGS += -static +BOOTLOADER_LDFLAGS += -Wl,-EL +BOOTLOADER_LDFLAGS += -Wl,-Map=$(@:.elf=.map) -Wl,--cref +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.rom.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.spiram_incompatible_fns.ld +BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.peripherals.ld + +BOOTLOADER_OBJ_DIRS = $(sort $(dir $(BOOTLOADER_OBJ))) +$(BOOTLOADER_OBJ): | $(BOOTLOADER_OBJ_DIRS) +$(BOOTLOADER_OBJ_DIRS): + $(MKDIR) -p $@ + +$(BUILD)/bootloader/%.o: %.c + $(call compile_c) + +$(BUILD)/bootloader.bin: $(BUILD)/bootloader.elf + $(ECHO) "Create $@" + $(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $< + +$(BUILD)/bootloader.elf: $(BOOTLOADER_OBJ) + $(ECHO) "LINK $@" + $(Q)$(CC) $(BOOTLOADER_LDFLAGS) -o $@ $(BOOTLOADER_LIBS) + +################################################################################ +# Declarations to build the partitions + +PYTHON2 ?= python2 +PART_SRC = partitions.csv + +$(BUILD)/partitions.bin: $(PART_SRC) + $(ECHO) "Create $@" + $(Q)$(PYTHON2) $(ESPCOMP)/partition_table/gen_esp32part.py -q $< $@ + +################################################################################ + +include $(TOP)/py/mkrules.mk diff --git a/ports/esp32/README.md b/ports/esp32/README.md new file mode 100644 index 0000000000..85df001e3f --- /dev/null +++ b/ports/esp32/README.md @@ -0,0 +1,202 @@ +MicroPython port to the ESP32 +============================= + +This is an experimental port of MicroPython to the Espressif ESP32 +microcontroller. It uses the ESP-IDF framework and MicroPython runs as +a task under FreeRTOS. + +Supported features include: +- REPL (Python prompt) over UART0. +- 16k stack for the MicroPython task and 96k Python heap. +- Many of MicroPython's features are enabled: unicode, arbitrary-precision + integers, single-precision floats, complex numbers, frozen bytecode, as + well as many of the internal modules. +- Internal filesystem using the flash (currently 2M in size). +- The machine module with GPIO, UART, SPI, software I2C, ADC, DAC, PWM, + TouchPad, WDT and Timer. +- The network module with WLAN (WiFi) support. + +Development of this ESP32 port was sponsored in part by Microbric Pty Ltd. + +Setting up the toolchain and ESP-IDF +------------------------------------ + +There are two main components that are needed to build the firmware: +- the Xtensa cross-compiler that targets the CPU in the ESP32 (this is + different to the compiler used by the ESP8266) +- the Espressif IDF (IoT development framework, aka SDK) + +The ESP-IDF changes quickly and MicroPython only supports a certain version. The +git hash of this version can be found by running `make` without a configured +`ESPIDF`. Then you can fetch only the given esp-idf using the following command: + + $ git clone https://github.com/espressif/esp-idf.git + $ git checkout + $ git submodule update --init --recursive + +The binary toolchain (binutils, gcc, etc.) can be installed using the following +guides: + + * [Linux installation](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) + * [MacOS installation](https://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html) + * [Windows installation](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html) + +If you are on a Windows machine then the +[Windows Subsystem for Linux](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide) +is the most efficient way to install the ESP32 toolchain and build the project. +If you use WSL then follow the +[Linux guidelines](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) +for the ESP-IDF instead of the Windows ones. + +The Espressif ESP-IDF instructions above only install pyserial for Python 2, +so if you're running Python 3 or a non-system Python you'll also need to +install `pyserial` (or `esptool`) so that the Makefile can flash the board +and set parameters: +```bash +$ pip install pyserial +``` + +Once everything is set up you should have a functioning toolchain with +prefix xtensa-esp32-elf- (or otherwise if you configured it differently) +as well as a copy of the ESP-IDF repository. You will need to update your `PATH` +environment variable to include the ESP32 toolchain. For example, you can issue +the following commands on (at least) Linux: + + $ export PATH=$PATH:$HOME/esp/crosstool-NG/builds/xtensa-esp32-elf/bin + +You can put this command in your `.profile` or `.bash_login`. + +You then need to set the `ESPIDF` environment/makefile variable to point to +the root of the ESP-IDF repository. You can set the variable in your PATH, +or at the command line when calling make, or in your own custom `makefile`. +The last option is recommended as it allows you to easily configure other +variables for the build. In that case, create a new file in the esp32 +directory called `makefile` and add the following lines to that file: +``` +ESPIDF = +#PORT = /dev/ttyUSB0 +#FLASH_MODE = qio +#FLASH_SIZE = 4MB +#CROSS_COMPILE = xtensa-esp32-elf- +#CONFIG_SPIRAM_SUPPORT = 1 + +include Makefile +``` +Be sure to enter the correct path to your local copy of the IDF repository +(and use `$(HOME)`, not tilde, to reference your home directory). +If your filesystem is case-insensitive then you'll need to use `GNUmakefile` +instead of `makefile`. +If the Xtensa cross-compiler is not in your path you can use the +`CROSS_COMPILE` variable to set its location. Other options of interest +are `PORT` for the serial port of your esp32 module, and `FLASH_MODE` +(which may need to be `dio` for some modules) +and `FLASH_SIZE`. See the Makefile for further information. + +Building the firmware +--------------------- + +The MicroPython cross-compiler must be built to pre-compile some of the +built-in scripts to bytecode. This can be done by (from the root of +this repository): +```bash +$ make -C mpy-cross +``` + +The ESP32 port has a dependency on Berkeley DB, which is an external +dependency (git submodule). You'll need to have git initialize that +module using the commands: +```bash +$ git submodule init lib/berkeley-db-1.xx +$ git submodule update +``` + +Then to build MicroPython for the ESP32 run: +```bash +$ cd ports/esp32 +$ make +``` +This will produce binary firmware images in the `build/` subdirectory +(three of them: bootloader.bin, partitions.bin and application.bin). + +To flash the firmware you must have your ESP32 module in the bootloader +mode and connected to a serial port on your PC. Refer to the documentation +for your particular ESP32 module for how to do this. The serial port and +flash settings are set in the `Makefile`, and can be overridden in your +local `makefile`; see above for more details. + +You will also need to have user permissions to access the /dev/ttyUSB0 device. +On Linux, you can enable this by adding your user to the `dialout` group, +and rebooting or logging out and in again. +```bash +$ sudo adduser dialout +``` + +If you are installing MicroPython to your module for the first time, or +after installing any other firmware, you should first erase the flash +completely: +```bash +$ make erase +``` + +To flash the MicroPython firmware to your ESP32 use: +```bash +$ make deploy +``` +This will use the `esptool.py` script (provided by ESP-IDF) to download the +binary images. + +Getting a Python prompt +----------------------- + +You can get a prompt via the serial port, via UART0, which is the same UART +that is used for programming the firmware. The baudrate for the REPL is +115200 and you can use a command such as: +```bash +$ picocom -b 115200 /dev/ttyUSB0 +``` + +Configuring the WiFi and using the board +---------------------------------------- + +The ESP32 port is designed to be (almost) equivalent to the ESP8266 in +terms of the modules and user-facing API. There are some small differences, +notably that the ESP32 does not automatically connect to the last access +point when booting up. But for the most part the documentation and tutorials +for the ESP8266 should apply to the ESP32 (at least for the components that +are implemented). + +See http://docs.micropython.org/en/latest/esp8266/esp8266/quickref.html for +a quick reference, and http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html +for a tutorial. + +The following function can be used to connect to a WiFi access point (you can +either pass in your own SSID and password, or change the defaults so you can +quickly call `wlan_connect()` and it just works): +```python +def wlan_connect(ssid='MYSSID', password='MYPASS'): + import network + wlan = network.WLAN(network.STA_IF) + if not wlan.active() or not wlan.isconnected(): + wlan.active(True) + print('connecting to:', ssid) + wlan.connect(ssid, password) + while not wlan.isconnected(): + pass + print('network config:', wlan.ifconfig()) +``` + +Note that some boards require you to configure the WiFi antenna before using +the WiFi. On Pycom boards like the LoPy and WiPy 2.0 you need to execute the +following code to select the internal antenna (best to put this line in your +boot.py file): +```python +import machine +antenna = machine.Pin(16, machine.Pin.OUT, value=0) +``` + +Troubleshooting +--------------- + +* Continuous reboots after programming: Ensure FLASH_MODE is correct for your + board (e.g. ESP-WROOM-32 should be DIO). Then perform a `make clean`, rebuild, + redeploy. diff --git a/ports/esp32/README.ulp.md b/ports/esp32/README.ulp.md new file mode 100644 index 0000000000..cbc5771a90 --- /dev/null +++ b/ports/esp32/README.ulp.md @@ -0,0 +1,126 @@ +# ULP + +To compile binarys for the ulp you need the ulp toolkit. Download it from https://github.com/espressif/binutils-esp32ulp/wiki#downloads +Then extract it, then add ```esp32ulp-elf-binutils/bin``` to your PATH + +## Example Makefile + +```make +ULP_S_SOURCES := main.S +ULP_APP_NAME := test +ULP_LD_SCRIPT := esp32.ulp.ld + +SRC_PATH := src +BUILD_PATH := build + +include $(ESPIDF)/components/ulp/Makefile.projbuild + +ULP_ELF := $(ULP_APP_NAME).elf +ULP_MAP := $(ULP_ELF:.elf=.map) +ULP_SYM := $(ULP_ELF:.elf=.sym) +ULP_BIN := $(ULP_ELF:.elf=.bin) +ULP_EXPORTS_LD := $(ULP_ELF:.elf=.ld) +ULP_EXPORTS_HEADER := $(ULP_ELF:.elf=.h) + +ULP_OBJECTS := $(notdir $(ULP_S_SOURCES:.S=.ulp.o)) +ULP_DEP := $(notdir $(ULP_S_SOURCES:.S=.ulp.d)) $(ULP_LD_SCRIPT:.ld=.d) +ULP_PREPROCESSED := $(notdir $(ULP_S_SOURCES:.S=.ulp.pS)) +ULP_LISTINGS := $(notdir $(ULP_S_SOURCES:.S=.ulp.lst)) + +.PHONY: all clean + +all: $(BUILD_PATH) $(BUILD_PATH)/$(ULP_BIN) + +clean: + rm -rf $(BUILD_PATH) + +$(BUILD_PATH): + mkdir $@ + +# Generate preprocessed linker file. +$(BUILD_PATH)/$(ULP_APP_NAME).ld: $(SRC_PATH)/$(ULP_LD_SCRIPT) + cpp -P $< -o $@ + +# Generate preprocessed assembly files. +# To inspect these preprocessed files, add a ".PRECIOUS: %.ulp.pS" rule. +$(BUILD_PATH)/%.ulp.pS: $(SRC_PATH)/%.S + cpp $< -o $@ + +# Compiled preprocessed files into object files. +$(BUILD_PATH)/%.ulp.o: $(BUILD_PATH)/%.ulp.pS + $(ULP_AS) -al=$(patsubst %.ulp.o,%.ulp.lst,$@) -o $@ $< + +# Link object files and generate map file +$(BUILD_PATH)/$(ULP_ELF): $(BUILD_PATH)/$(ULP_OBJECTS) $(BUILD_PATH)/$(ULP_APP_NAME).ld + $(ULP_LD) -o $@ -A elf32-esp32ulp -Map=$(BUILD_PATH)/$(ULP_MAP) -T $(BUILD_PATH)/$(ULP_APP_NAME).ld $< + +# Dump the list of global symbols in a convenient format. +$(ULP_SYM): $(ULP_ELF) + $(ULP_NM) -g -f posix $< > $@ + +# Dump the binary for inclusion into the project +$(BUILD_PATH)/$(ULP_BIN): $(BUILD_PATH)/$(ULP_ELF) + $(ULP_OBJCOPY) -O binary $< $@ +``` + +## Example linker script for the ulp +``` +#define ULP_BIN_MAGIC 0x00706c75 +#define HEADER_SIZE 12 +#define CONFIG_ULP_COPROC_RESERVE_MEM 4096 + +MEMORY +{ + ram(RW) : ORIGIN = 0, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM +} + +SECTIONS +{ + .text : AT(HEADER_SIZE) + { + *(.text) + } >ram + .data : + { + . = ALIGN(4); + *(.data) + } >ram + .bss : + { + . = ALIGN(4); + *(.bss) + } >ram + + .header : AT(0) + { + LONG(ULP_BIN_MAGIC) + SHORT(LOADADDR(.text)) + SHORT(SIZEOF(.text)) + SHORT(SIZEOF(.data)) + SHORT(SIZEOF(.bss)) + } +} +``` + +## Example ulp code +```asm +move R3, 99 +move R0, 10 + +# mem[R0+0] = R3 +st R3, R0, 0 + +HALT +``` + +## Example python code using the ulp +```python +import esp32 +import time + +u = esp32.ULP() +with open('test.bin', 'rb') as f: + b = f.read() +u.load_binary(0,b) +u.run(0) +``` diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld new file mode 100644 index 0000000000..716e9ac1d8 --- /dev/null +++ b/ports/esp32/esp32.custom_common.ld @@ -0,0 +1,254 @@ +/* Default entry point: */ +ENTRY(call_start_cpu0); + +SECTIONS +{ + /* RTC fast memory holds RTC wake stub code, + including from any source file named rtc_wake_stub*.c + */ + .rtc.text : + { + . = ALIGN(4); + *(.rtc.literal .rtc.text) + *rtc_wake_stub*.o(.literal .text .literal.* .text.*) + } > rtc_iram_seg + + /* RTC slow memory holds RTC wake stub + data/rodata, including from any source file + named rtc_wake_stub*.c + */ + .rtc.data : + { + _rtc_data_start = ABSOLUTE(.); + *(.rtc.data) + *(.rtc.rodata) + *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*) + _rtc_data_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* RTC bss, from any source file named rtc_wake_stub*.c */ + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + *rtc_wake_stub*.o(.bss .bss.*) + *rtc_wake_stub*.o(COMMON) + _rtc_bss_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* This section holds data that should not be initialized at power up + and will be retained during deep sleep. The section located in + RTC SLOW Memory area. User data marked with RTC_NOINIT_ATTR will be placed + into this section. See the file "esp_attr.h" for more information. + */ + .rtc_noinit (NOLOAD): + { + . = ALIGN(4); + _rtc_noinit_start = ABSOLUTE(.); + *(.rtc_noinit .rtc_noinit.*) + . = ALIGN(4) ; + _rtc_noinit_end = ABSOLUTE(.); + } > rtc_slow_seg + + /* Send .iram0 code to iram */ + .iram0.vectors : + { + /* Vectors go to IRAM */ + _init_start = ABSOLUTE(.); + /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */ + . = 0x0; + KEEP(*(.WindowVectors.text)); + . = 0x180; + KEEP(*(.Level2InterruptVector.text)); + . = 0x1c0; + KEEP(*(.Level3InterruptVector.text)); + . = 0x200; + KEEP(*(.Level4InterruptVector.text)); + . = 0x240; + KEEP(*(.Level5InterruptVector.text)); + . = 0x280; + KEEP(*(.DebugExceptionVector.text)); + . = 0x2c0; + KEEP(*(.NMIExceptionVector.text)); + . = 0x300; + KEEP(*(.KernelExceptionVector.text)); + . = 0x340; + KEEP(*(.UserExceptionVector.text)); + . = 0x3C0; + KEEP(*(.DoubleExceptionVector.text)); + . = 0x400; + *(.*Vector.literal) + + *(.UserEnter.literal); + *(.UserEnter.text); + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + _init_end = ABSOLUTE(.); + + /* This goes here, not at top of linker script, so addr2line finds it last, + and uses it in preference to the first symbol in IRAM */ + _iram_start = ABSOLUTE(0); + } > iram0_0_seg + + .iram0.text : + { + /* Code marked as runnning out of IRAM */ + _iram_text_start = ABSOLUTE(.); + *(.iram1 .iram1.*) + *freertos/*(.literal .text .literal.* .text.*) + *heap/multi_heap.o(.literal .text .literal.* .text.*) + *heap/multi_heap_poisoning.o(.literal .text .literal.* .text.*) + *esp32/panic.o(.literal .text .literal.* .text.*) + *esp32/core_dump.o(.literal .text .literal.* .text.*) + *app_trace/*(.literal .text .literal.* .text.*) + *xtensa-debug-module/eri.o(.literal .text .literal.* .text.*) + *librtc.a:(.literal .text .literal.* .text.*) + *soc/esp32/*(.literal .text .literal.* .text.*) + *libhal.a:(.literal .text .literal.* .text.*) + *libgcc.a:lib2funcs.o(.literal .text .literal.* .text.*) + *spi_flash/spi_flash_rom_patch.o(.literal .text .literal.* .text.*) + *libgcov.a:(.literal .text .literal.* .text.*) + INCLUDE esp32.spiram.rom-functions-iram.ld + *py/scheduler.o*(.literal .text .literal.* .text.*) + _iram_text_end = ABSOLUTE(.); + } > iram0_0_seg + + .dram0.data : + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + *(.dram1 .dram1.*) + *esp32/panic.o(.rodata .rodata.*) + *libphy.a:(.rodata .rodata.*) + *soc/esp32/rtc_clk.o(.rodata .rodata.*) + *app_trace/app_trace.o(.rodata .rodata.*) + *libgcov.a:(.rodata .rodata.*) + *heap/multi_heap.o(.rodata .rodata.*) + *heap/multi_heap_poisoning.o(.rodata .rodata.*) + INCLUDE esp32.spiram.rom-functions-dram.ld + _data_end = ABSOLUTE(.); + . = ALIGN(4); + } > dram0_0_seg + + /*This section holds data that should not be initialized at power up. + The section located in Internal SRAM memory region. The macro _NOINIT + can be used as attribute to place data into this section. + See the esp_attr.h file for more information. + */ + .noinit (NOLOAD): + { + . = ALIGN(4); + _noinit_start = ABSOLUTE(.); + *(.noinit .noinit.*) + . = ALIGN(4) ; + _noinit_end = ABSOLUTE(.); + } > dram0_0_seg + + /* Shared RAM */ + .dram0.bss (NOLOAD) : + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.share.mem) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + /* The heap starts right after end of this section */ + _heap_start = ABSOLUTE(.); + } > dram0_0_seg + + .flash.rodata : + { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table .gcc_except_table.*) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + . = (. + 3) & ~ 3; + __eh_frame = ABSOLUTE(.); + KEEP(*(.eh_frame)) + . = (. + 7) & ~ 3; + /* C++ constructor and destructor tables, properly ordered: */ + __init_array_start = ABSOLUTE(.); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __init_array_end = ABSOLUTE(.); + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS_ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + _rodata_end = ABSOLUTE(.); + /* Literals are also RO data. */ + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + . = ALIGN(4); + _thread_local_start = ABSOLUTE(.); + *(.tdata) + *(.tdata.*) + *(.tbss) + *(.tbss.*) + _thread_local_end = ABSOLUTE(.); + . = ALIGN(4); + } >drom0_0_seg + + .flash.text : + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + + /* Similar to _iram_start, this symbol goes here so it is + resolved by addr2line in preference to the first symbol in + the flash.text segment. + */ + _flash_cache_start = ABSOLUTE(0); + } >iram0_2_seg +} diff --git a/ports/esp32/esp32_ulp.c b/ports/esp32/esp32_ulp.c new file mode 100644 index 0000000000..3772639f44 --- /dev/null +++ b/ports/esp32/esp32_ulp.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 "Andreas Valder" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" + +#include "esp32/ulp.h" +#include "esp_err.h" + +typedef struct _esp32_ulp_obj_t { + mp_obj_base_t base; +} esp32_ulp_obj_t; + +const mp_obj_type_t esp32_ulp_type; + +// singleton ULP object +STATIC const esp32_ulp_obj_t esp32_ulp_obj = {{&esp32_ulp_type}}; + +STATIC mp_obj_t esp32_ulp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&esp32_ulp_obj; +} + +STATIC mp_obj_t esp32_ulp_set_wakeup_period(mp_obj_t self_in, mp_obj_t period_index_in, mp_obj_t period_us_in) { + mp_uint_t period_index = mp_obj_get_int(period_index_in); + mp_uint_t period_us = mp_obj_get_int(period_us_in); + int _errno = ulp_set_wakeup_period(period_index, period_us); + if (_errno != ESP_OK) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_set_wakeup_period_obj, esp32_ulp_set_wakeup_period); + +STATIC mp_obj_t esp32_ulp_load_binary(mp_obj_t self_in, mp_obj_t load_addr_in, mp_obj_t program_binary_in) { + mp_uint_t load_addr = mp_obj_get_int(load_addr_in); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(program_binary_in, &bufinfo, MP_BUFFER_READ); + + int _errno = ulp_load_binary(load_addr, bufinfo.buf, bufinfo.len/sizeof(uint32_t)); + if (_errno != ESP_OK) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_load_binary_obj, esp32_ulp_load_binary); + +STATIC mp_obj_t esp32_ulp_run(mp_obj_t self_in, mp_obj_t entry_point_in) { + mp_uint_t entry_point = mp_obj_get_int(entry_point_in); + int _errno = ulp_run(entry_point/sizeof(uint32_t)); + if (_errno != ESP_OK) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp32_ulp_run_obj, esp32_ulp_run); + +STATIC const mp_rom_map_elem_t esp32_ulp_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&esp32_ulp_set_wakeup_period_obj) }, + { MP_ROM_QSTR(MP_QSTR_load_binary), MP_ROM_PTR(&esp32_ulp_load_binary_obj) }, + { MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&esp32_ulp_run_obj) }, + { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ULP_COPROC_RESERVE_MEM) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp32_ulp_locals_dict, esp32_ulp_locals_dict_table); + +const mp_obj_type_t esp32_ulp_type = { + { &mp_type_type }, + .name = MP_QSTR_ULP, + .make_new = esp32_ulp_make_new, + .locals_dict = (mp_obj_t)&esp32_ulp_locals_dict, +}; diff --git a/ports/esp32/espneopixel.c b/ports/esp32/espneopixel.c new file mode 100644 index 0000000000..829c8b1c80 --- /dev/null +++ b/ports/esp32/espneopixel.c @@ -0,0 +1,53 @@ +// Original version from https://github.com/adafruit/Adafruit_NeoPixel +// Modifications by dpgeorge to support auto-CPU-frequency detection + +// This is a mash-up of the Due show() code + insights from Michael Miller's +// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus +// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution. + +#include "py/mpconfig.h" +#include "py/mphal.h" +#include "modesp.h" + +void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing) { + uint8_t *p, *end, pix, mask; + uint32_t t, time0, time1, period, c, startTime, pinMask; + + pinMask = 1 << pin; + p = pixels; + end = p + numBytes; + pix = *p++; + mask = 0x80; + startTime = 0; + + uint32_t fcpu = ets_get_cpu_frequency() * 1000000; + + if (timing == 1) { + // 800 KHz + time0 = (fcpu * 0.35) / 1000000; // 0.35us + time1 = (fcpu * 0.8) / 1000000; // 0.8us + period = (fcpu * 1.25) / 1000000; // 1.25us per bit + } else { + // 400 KHz + time0 = (fcpu * 0.5) / 1000000; // 0.35us + time1 = (fcpu * 1.2) / 1000000; // 0.8us + period = (fcpu * 2.5) / 1000000; // 1.25us per bit + } + + uint32_t irq_state = mp_hal_quiet_timing_enter(); + for (t = time0;; t = time0) { + if (pix & mask) t = time1; // Bit high duration + while (((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start + GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, pinMask); // Set high + startTime = c; // Save start time + while (((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration + GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, pinMask); // Set low + if (!(mask >>= 1)) { // Next bit/byte + if(p >= end) break; + pix = *p++; + mask = 0x80; + } + } + while ((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit + mp_hal_quiet_timing_exit(irq_state); +} diff --git a/ports/esp32/esponewire.c b/ports/esp32/esponewire.c new file mode 100644 index 0000000000..781616cbe4 --- /dev/null +++ b/ports/esp32/esponewire.c @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "esp8266/esponewire.h" + +#define TIMING_RESET1 (0) +#define TIMING_RESET2 (1) +#define TIMING_RESET3 (2) +#define TIMING_READ1 (3) +#define TIMING_READ2 (4) +#define TIMING_READ3 (5) +#define TIMING_WRITE1 (6) +#define TIMING_WRITE2 (7) +#define TIMING_WRITE3 (8) + +uint16_t esp_onewire_timings[9] = {480, 40, 420, 5, 5, 40, 10, 50, 10}; + +#define DELAY_US mp_hal_delay_us_fast + +int esp_onewire_reset(mp_hal_pin_obj_t pin) { + mp_hal_pin_write(pin, 0); + DELAY_US(esp_onewire_timings[TIMING_RESET1]); + uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_hal_pin_write(pin, 1); + DELAY_US(esp_onewire_timings[TIMING_RESET2]); + int status = !mp_hal_pin_read(pin); + MICROPY_END_ATOMIC_SECTION(i); + DELAY_US(esp_onewire_timings[TIMING_RESET3]); + return status; +} + +int esp_onewire_readbit(mp_hal_pin_obj_t pin) { + mp_hal_pin_write(pin, 1); + uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_hal_pin_write(pin, 0); + DELAY_US(esp_onewire_timings[TIMING_READ1]); + mp_hal_pin_write(pin, 1); + DELAY_US(esp_onewire_timings[TIMING_READ2]); + int value = mp_hal_pin_read(pin); + MICROPY_END_ATOMIC_SECTION(i); + DELAY_US(esp_onewire_timings[TIMING_READ3]); + return value; +} + +void esp_onewire_writebit(mp_hal_pin_obj_t pin, int value) { + uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_hal_pin_write(pin, 0); + DELAY_US(esp_onewire_timings[TIMING_WRITE1]); + if (value) { + mp_hal_pin_write(pin, 1); + } + DELAY_US(esp_onewire_timings[TIMING_WRITE2]); + mp_hal_pin_write(pin, 1); + DELAY_US(esp_onewire_timings[TIMING_WRITE3]); + MICROPY_END_ATOMIC_SECTION(i); +} diff --git a/ports/esp32/fatfs_port.c b/ports/esp32/fatfs_port.c new file mode 100644 index 0000000000..880324ed82 --- /dev/null +++ b/ports/esp32/fatfs_port.c @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "lib/oofatfs/ff.h" +#include "timeutils.h" + +DWORD get_fattime(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + timeutils_struct_time_t tm; + timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); + + return (((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) | + ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1)); +} diff --git a/ports/esp32/gccollect.c b/ports/esp32/gccollect.c new file mode 100644 index 0000000000..9843cef008 --- /dev/null +++ b/ports/esp32/gccollect.c @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * Copyright (c) 2017 Pycom Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpconfig.h" +#include "py/mpstate.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "gccollect.h" +#include "soc/cpu.h" +#include "xtensa/hal.h" + + +static void gc_collect_inner(int level) { + if (level < XCHAL_NUM_AREGS / 8) { + gc_collect_inner(level + 1); + if (level != 0) { + return; + } + } + + if (level == XCHAL_NUM_AREGS / 8) { + // get the sp + volatile uint32_t sp = (uint32_t)get_sp(); + gc_collect_root((void**)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t)); + return; + } + + // trace root pointers from any threads + #if MICROPY_PY_THREAD + mp_thread_gc_others(); + #endif +} + +void gc_collect(void) { + gc_collect_start(); + gc_collect_inner(0); + gc_collect_end(); +} diff --git a/ports/esp32/gccollect.h b/ports/esp32/gccollect.h new file mode 100644 index 0000000000..fe02cc62be --- /dev/null +++ b/ports/esp32/gccollect.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +extern uint32_t _text_start; +extern uint32_t _text_end; +extern uint32_t _irom0_text_start; +extern uint32_t _irom0_text_end; +extern uint32_t _data_start; +extern uint32_t _data_end; +extern uint32_t _rodata_start; +extern uint32_t _rodata_end; +extern uint32_t _bss_start; +extern uint32_t _bss_end; +extern uint32_t _heap_start; +extern uint32_t _heap_end; + +void gc_collect(void); diff --git a/ports/esp32/help.c b/ports/esp32/help.c new file mode 100644 index 0000000000..95d115c563 --- /dev/null +++ b/ports/esp32/help.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/builtin.h" + +const char esp32_help_text[] = +"Welcome to MicroPython on the ESP32!\n" +"\n" +"For generic online docs please visit http://docs.micropython.org/\n" +"\n" +"For access to the hardware use the 'machine' module:\n" +"\n" +"import machine\n" +"pin12 = machine.Pin(12, machine.Pin.OUT)\n" +"pin12.value(1)\n" +"pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)\n" +"print(pin13.value())\n" +"i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22))\n" +"i2c.scan()\n" +"i2c.writeto(addr, b'1234')\n" +"i2c.readfrom(addr, 4)\n" +"\n" +"Basic WiFi configuration:\n" +"\n" +"import network\n" +"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n" +"sta_if.scan() # Scan for available access points\n" +"sta_if.connect(\"\", \"\") # Connect to an AP\n" +"sta_if.isconnected() # Check for successful connection\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +"For a list of available modules, type help('modules')\n" +; diff --git a/ports/esp32/machine_adc.c b/ports/esp32/machine_adc.c new file mode 100644 index 0000000000..d62f362e96 --- /dev/null +++ b/ports/esp32/machine_adc.c @@ -0,0 +1,132 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "esp_log.h" + +#include "driver/gpio.h" +#include "driver/adc.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" + +typedef struct _madc_obj_t { + mp_obj_base_t base; + gpio_num_t gpio_id; + adc1_channel_t adc1_id; +} madc_obj_t; + +STATIC const madc_obj_t madc_obj[] = { + {{&machine_adc_type}, GPIO_NUM_36, ADC1_CHANNEL_0}, + {{&machine_adc_type}, GPIO_NUM_37, ADC1_CHANNEL_1}, + {{&machine_adc_type}, GPIO_NUM_38, ADC1_CHANNEL_2}, + {{&machine_adc_type}, GPIO_NUM_39, ADC1_CHANNEL_3}, + {{&machine_adc_type}, GPIO_NUM_32, ADC1_CHANNEL_4}, + {{&machine_adc_type}, GPIO_NUM_33, ADC1_CHANNEL_5}, + {{&machine_adc_type}, GPIO_NUM_34, ADC1_CHANNEL_6}, + {{&machine_adc_type}, GPIO_NUM_35, ADC1_CHANNEL_7}, +}; + +STATIC mp_obj_t madc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + + static int initialized = 0; + if (!initialized) { + adc1_config_width(ADC_WIDTH_12Bit); + initialized = 1; + } + + mp_arg_check_num(n_args, n_kw, 1, 1, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + const madc_obj_t *self = NULL; + for (int i = 0; i < MP_ARRAY_SIZE(madc_obj); i++) { + if (pin_id == madc_obj[i].gpio_id) { self = &madc_obj[i]; break; } + } + if (!self) mp_raise_ValueError("invalid Pin for ADC"); + esp_err_t err = adc1_config_channel_atten(self->adc1_id, ADC_ATTEN_0db); + if (err == ESP_OK) return MP_OBJ_FROM_PTR(self); + mp_raise_ValueError("Parameter Error"); +} + +STATIC void madc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + madc_obj_t *self = self_in; + mp_printf(print, "ADC(Pin(%u))", self->gpio_id); +} + +STATIC mp_obj_t madc_read(mp_obj_t self_in) { + madc_obj_t *self = self_in; + int val = adc1_get_raw(self->adc1_id); + if (val == -1) mp_raise_ValueError("Parameter Error"); + return MP_OBJ_NEW_SMALL_INT(val); +} +MP_DEFINE_CONST_FUN_OBJ_1(madc_read_obj, madc_read); + +STATIC mp_obj_t madc_atten(mp_obj_t self_in, mp_obj_t atten_in) { + madc_obj_t *self = self_in; + adc_atten_t atten = mp_obj_get_int(atten_in); + esp_err_t err = adc1_config_channel_atten(self->adc1_id, atten); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Parameter Error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(madc_atten_obj, madc_atten); + +STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) { + adc_bits_width_t width = mp_obj_get_int(width_in); + esp_err_t err = adc1_config_width(width); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Parameter Error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(madc_width_fun_obj, madc_width); +MP_DEFINE_CONST_CLASSMETHOD_OBJ(madc_width_obj, MP_ROM_PTR(&madc_width_fun_obj)); + +STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&madc_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_atten), MP_ROM_PTR(&madc_atten_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&madc_width_obj) }, + + { MP_ROM_QSTR(MP_QSTR_ATTN_0DB), MP_ROM_INT(ADC_ATTEN_0db) }, + { MP_ROM_QSTR(MP_QSTR_ATTN_2_5DB), MP_ROM_INT(ADC_ATTEN_2_5db) }, + { MP_ROM_QSTR(MP_QSTR_ATTN_6DB), MP_ROM_INT(ADC_ATTEN_6db) }, + { MP_ROM_QSTR(MP_QSTR_ATTN_11DB), MP_ROM_INT(ADC_ATTEN_11db) }, + + { MP_ROM_QSTR(MP_QSTR_WIDTH_9BIT), MP_ROM_INT(ADC_WIDTH_9Bit) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) }, + { MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) }, +}; + +STATIC MP_DEFINE_CONST_DICT(madc_locals_dict, madc_locals_dict_table); + +const mp_obj_type_t machine_adc_type = { + { &mp_type_type }, + .name = MP_QSTR_ADC, + .print = madc_print, + .make_new = madc_make_new, + .locals_dict = (mp_obj_t)&madc_locals_dict, +}; diff --git a/ports/esp32/machine_dac.c b/ports/esp32/machine_dac.c new file mode 100644 index 0000000000..bd0804ec41 --- /dev/null +++ b/ports/esp32/machine_dac.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "esp_log.h" + +#include "driver/gpio.h" +#include "driver/dac.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" + +typedef struct _mdac_obj_t { + mp_obj_base_t base; + gpio_num_t gpio_id; + dac_channel_t dac_id; +} mdac_obj_t; + +STATIC const mdac_obj_t mdac_obj[] = { + {{&machine_dac_type}, GPIO_NUM_25, DAC_CHANNEL_1}, + {{&machine_dac_type}, GPIO_NUM_26, DAC_CHANNEL_2}, +}; + +STATIC mp_obj_t mdac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + + mp_arg_check_num(n_args, n_kw, 1, 1, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + const mdac_obj_t *self = NULL; + for (int i = 0; i < MP_ARRAY_SIZE(mdac_obj); i++) { + if (pin_id == mdac_obj[i].gpio_id) { self = &mdac_obj[i]; break; } + } + if (!self) mp_raise_ValueError("invalid Pin for DAC"); + + esp_err_t err = dac_output_enable(self->dac_id); + if (err == ESP_OK) { + err = dac_output_voltage(self->dac_id, 0); + } + if (err == ESP_OK) return MP_OBJ_FROM_PTR(self); + mp_raise_ValueError("Parameter Error"); +} + +STATIC void mdac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + mdac_obj_t *self = self_in; + mp_printf(print, "DAC(Pin(%u))", self->gpio_id); +} + +STATIC mp_obj_t mdac_write(mp_obj_t self_in, mp_obj_t value_in) { + mdac_obj_t *self = self_in; + int value = mp_obj_get_int(value_in); + if (value < 0 || value > 255) mp_raise_ValueError("Value out of range"); + + esp_err_t err = dac_output_voltage(self->dac_id, value); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Parameter Error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(mdac_write_obj, mdac_write); + +STATIC const mp_rom_map_elem_t mdac_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mdac_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mdac_locals_dict, mdac_locals_dict_table); + +const mp_obj_type_t machine_dac_type = { + { &mp_type_type }, + .name = MP_QSTR_DAC, + .print = mdac_print, + .make_new = mdac_make_new, + .locals_dict = (mp_obj_t)&mdac_locals_dict, +}; diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c new file mode 100644 index 0000000000..d011ce53e3 --- /dev/null +++ b/ports/esp32/machine_hw_spi.c @@ -0,0 +1,390 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" +#include "extmod/machine_spi.h" +#include "modmachine.h" + +#include "driver/spi_master.h" + +#define MP_HW_SPI_MAX_XFER_BYTES (4092) +#define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8 + +typedef struct _machine_hw_spi_obj_t { + mp_obj_base_t base; + spi_host_device_t host; + uint32_t baudrate; + uint8_t polarity; + uint8_t phase; + uint8_t bits; + uint8_t firstbit; + int8_t sck; + int8_t mosi; + int8_t miso; + spi_device_handle_t spi; + enum { + MACHINE_HW_SPI_STATE_NONE, + MACHINE_HW_SPI_STATE_INIT, + MACHINE_HW_SPI_STATE_DEINIT + } state; +} machine_hw_spi_obj_t; + +STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) { + switch (spi_bus_remove_device(self->spi)) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + return; + + case ESP_ERR_INVALID_STATE: + mp_raise_msg(&mp_type_OSError, "SPI device already freed"); + return; + } + + switch (spi_bus_free(self->host)) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + return; + + case ESP_ERR_INVALID_STATE: + mp_raise_msg(&mp_type_OSError, "SPI bus already freed"); + return; + } + + int8_t pins[3] = {self->miso, self->mosi, self->sck}; + + for (int i = 0; i < 3; i++) { + if (pins[i] != -1) { + gpio_pad_select_gpio(pins[i]); + gpio_matrix_out(pins[i], SIG_GPIO_OUT_IDX, false, false); + gpio_set_direction(pins[i], GPIO_MODE_INPUT); + } + } +} + +STATIC void machine_hw_spi_init_internal( + machine_hw_spi_obj_t *self, + int8_t host, + int32_t baudrate, + int8_t polarity, + int8_t phase, + int8_t bits, + int8_t firstbit, + int8_t sck, + int8_t mosi, + int8_t miso) { + + // if we're not initialized, then we're + // implicitly 'changed', since this is the init routine + bool changed = self->state != MACHINE_HW_SPI_STATE_INIT; + + esp_err_t ret; + + machine_hw_spi_obj_t old_self = *self; + + if (host != -1 && host != self->host) { + self->host = host; + changed = true; + } + + if (baudrate != -1 && baudrate != self->baudrate) { + self->baudrate = baudrate; + changed = true; + } + + if (polarity != -1 && polarity != self->polarity) { + self->polarity = polarity; + changed = true; + } + + if (phase != -1 && phase != self->phase) { + self->phase = phase; + changed = true; + } + + if (bits != -1 && bits != self->bits) { + self->bits = bits; + changed = true; + } + + if (firstbit != -1 && firstbit != self->firstbit) { + self->firstbit = firstbit; + changed = true; + } + + if (sck != -2 && sck != self->sck) { + self->sck = sck; + changed = true; + } + + if (mosi != -2 && mosi != self->mosi) { + self->mosi = mosi; + changed = true; + } + + if (miso != -2 && miso != self->miso) { + self->miso = miso; + changed = true; + } + + if (self->host != HSPI_HOST && self->host != VSPI_HOST) { + mp_raise_ValueError("SPI ID must be either HSPI(1) or VSPI(2)"); + } + + if (changed) { + if (self->state == MACHINE_HW_SPI_STATE_INIT) { + self->state = MACHINE_HW_SPI_STATE_DEINIT; + machine_hw_spi_deinit_internal(&old_self); + } + } else { + return; // no changes + } + + spi_bus_config_t buscfg = { + .miso_io_num = self->miso, + .mosi_io_num = self->mosi, + .sclk_io_num = self->sck, + .quadwp_io_num = -1, + .quadhd_io_num = -1 + }; + + spi_device_interface_config_t devcfg = { + .clock_speed_hz = self->baudrate, + .mode = self->phase | (self->polarity << 1), + .spics_io_num = -1, // No CS pin + .queue_size = 1, + .flags = self->firstbit == MICROPY_PY_MACHINE_SPI_LSB ? SPI_DEVICE_TXBIT_LSBFIRST | SPI_DEVICE_RXBIT_LSBFIRST : 0, + .pre_cb = NULL + }; + + //Initialize the SPI bus + // FIXME: Does the DMA matter? There are two + + ret = spi_bus_initialize(self->host, &buscfg, 1); + switch (ret) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + return; + + case ESP_ERR_INVALID_STATE: + mp_raise_msg(&mp_type_OSError, "SPI device already in use"); + return; + } + + ret = spi_bus_add_device(self->host, &devcfg, &self->spi); + switch (ret) { + case ESP_ERR_INVALID_ARG: + mp_raise_msg(&mp_type_OSError, "invalid configuration"); + spi_bus_free(self->host); + return; + + case ESP_ERR_NO_MEM: + mp_raise_msg(&mp_type_OSError, "out of memory"); + spi_bus_free(self->host); + return; + + case ESP_ERR_NOT_FOUND: + mp_raise_msg(&mp_type_OSError, "no free slots"); + spi_bus_free(self->host); + return; + } + self->state = MACHINE_HW_SPI_STATE_INIT; +} + +STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) { + machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in; + if (self->state == MACHINE_HW_SPI_STATE_INIT) { + self->state = MACHINE_HW_SPI_STATE_DEINIT; + machine_hw_spi_deinit_internal(self); + } +} + +STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->state == MACHINE_HW_SPI_STATE_DEINIT) { + mp_raise_msg(&mp_type_OSError, "transfer on deinitialized SPI"); + return; + } + + struct spi_transaction_t transaction = { 0 }; + + // Round to nearest whole set of bits + int bits_to_send = len * 8 / self->bits * self->bits; + + + if (len <= 4) { + if (src != NULL) { + memcpy(&transaction.tx_data, src, len); + } + + transaction.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA; + transaction.length = bits_to_send; + spi_device_transmit(self->spi, &transaction); + + if (dest != NULL) { + memcpy(dest, &transaction.rx_data, len); + } + } else { + int offset = 0; + int bits_remaining = bits_to_send; + + while (bits_remaining) { + memset(&transaction, 0, sizeof(transaction)); + + transaction.length = + bits_remaining > MP_HW_SPI_MAX_XFER_BITS ? MP_HW_SPI_MAX_XFER_BITS : bits_remaining; + + if (src != NULL) { + transaction.tx_buffer = src + offset; + } + if (dest != NULL) { + transaction.rx_buffer = dest + offset; + } + + spi_device_transmit(self->spi, &transaction); + bits_remaining -= transaction.length; + + // doesn't need ceil(); loop ends when bits_remaining is 0 + offset += transaction.length / 8; + } + } +} + +/******************************************************************************/ +// MicroPython bindings for hw_spi + +STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "SPI(id=%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%u, sck=%d, mosi=%d, miso=%d)", + self->host, self->baudrate, self->polarity, + self->phase, self->bits, self->firstbit, + self->sck, self->mosi, self->miso); +} + +STATIC void machine_hw_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in; + + enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), + allowed_args, args); + int8_t sck, mosi, miso; + + if (args[ARG_sck].u_obj == MP_OBJ_NULL) { + sck = -2; + } else if (args[ARG_sck].u_obj == mp_const_none) { + sck = -1; + } else { + sck = machine_pin_get_id(args[ARG_sck].u_obj); + } + + if (args[ARG_miso].u_obj == MP_OBJ_NULL) { + miso = -2; + } else if (args[ARG_miso].u_obj == mp_const_none) { + miso = -1; + } else { + miso = machine_pin_get_id(args[ARG_miso].u_obj); + } + + if (args[ARG_mosi].u_obj == MP_OBJ_NULL) { + mosi = -2; + } else if (args[ARG_mosi].u_obj == mp_const_none) { + mosi = -1; + } else { + mosi = machine_pin_get_id(args[ARG_mosi].u_obj); + } + + machine_hw_spi_init_internal(self, args[ARG_id].u_int, args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int, + args[ARG_firstbit].u_int, sck, mosi, miso); +} + +mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + machine_hw_spi_obj_t *self = m_new_obj(machine_hw_spi_obj_t); + self->base.type = &machine_hw_spi_type; + + machine_hw_spi_init_internal( + self, + args[ARG_id].u_int, + args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, + args[ARG_phase].u_int, + args[ARG_bits].u_int, + args[ARG_firstbit].u_int, + args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj), + args[ARG_mosi].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_mosi].u_obj), + args[ARG_miso].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_miso].u_obj)); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC const mp_machine_spi_p_t machine_hw_spi_p = { + .init = machine_hw_spi_init, + .deinit = machine_hw_spi_deinit, + .transfer = machine_hw_spi_transfer, +}; + +const mp_obj_type_t machine_hw_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .print = machine_hw_spi_print, + .make_new = machine_hw_spi_make_new, + .protocol = &machine_hw_spi_p, + .locals_dict = (mp_obj_dict_t *) &mp_machine_spi_locals_dict, +}; diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c new file mode 100644 index 0000000000..2a26d6bfb0 --- /dev/null +++ b/ports/esp32/machine_pin.c @@ -0,0 +1,414 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "driver/gpio.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" +#include "extmod/virtpin.h" +#include "machine_rtc.h" +#include "modesp32.h" + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + gpio_num_t id; +} machine_pin_obj_t; + +typedef struct _machine_pin_irq_obj_t { + mp_obj_base_t base; + gpio_num_t id; +} machine_pin_irq_obj_t; + +STATIC const machine_pin_obj_t machine_pin_obj[] = { + {{&machine_pin_type}, GPIO_NUM_0}, + {{&machine_pin_type}, GPIO_NUM_1}, + {{&machine_pin_type}, GPIO_NUM_2}, + {{&machine_pin_type}, GPIO_NUM_3}, + {{&machine_pin_type}, GPIO_NUM_4}, + {{&machine_pin_type}, GPIO_NUM_5}, + {{&machine_pin_type}, GPIO_NUM_6}, + {{&machine_pin_type}, GPIO_NUM_7}, + {{&machine_pin_type}, GPIO_NUM_8}, + {{&machine_pin_type}, GPIO_NUM_9}, + {{&machine_pin_type}, GPIO_NUM_10}, + {{&machine_pin_type}, GPIO_NUM_11}, + {{&machine_pin_type}, GPIO_NUM_12}, + {{&machine_pin_type}, GPIO_NUM_13}, + {{&machine_pin_type}, GPIO_NUM_14}, + {{&machine_pin_type}, GPIO_NUM_15}, + {{&machine_pin_type}, GPIO_NUM_16}, + {{&machine_pin_type}, GPIO_NUM_17}, + {{&machine_pin_type}, GPIO_NUM_18}, + {{&machine_pin_type}, GPIO_NUM_19}, + {{NULL}, -1}, + {{&machine_pin_type}, GPIO_NUM_21}, + {{&machine_pin_type}, GPIO_NUM_22}, + {{&machine_pin_type}, GPIO_NUM_23}, + {{NULL}, -1}, + {{&machine_pin_type}, GPIO_NUM_25}, + {{&machine_pin_type}, GPIO_NUM_26}, + {{&machine_pin_type}, GPIO_NUM_27}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{&machine_pin_type}, GPIO_NUM_32}, + {{&machine_pin_type}, GPIO_NUM_33}, + {{&machine_pin_type}, GPIO_NUM_34}, + {{&machine_pin_type}, GPIO_NUM_35}, + {{&machine_pin_type}, GPIO_NUM_36}, + {{&machine_pin_type}, GPIO_NUM_37}, + {{&machine_pin_type}, GPIO_NUM_38}, + {{&machine_pin_type}, GPIO_NUM_39}, +}; + +// forward declaration +STATIC const machine_pin_irq_obj_t machine_pin_irq_object[]; + +void machine_pins_init(void) { + static bool did_install = false; + if (!did_install) { + gpio_install_isr_service(0); + did_install = true; + } + memset(&MP_STATE_PORT(machine_pin_irq_handler[0]), 0, sizeof(MP_STATE_PORT(machine_pin_irq_handler))); +} + +void machine_pins_deinit(void) { + for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) { + if (machine_pin_obj[i].id != (gpio_num_t)-1) { + gpio_isr_handler_remove(machine_pin_obj[i].id); + } + } +} + +STATIC void IRAM_ATTR machine_pin_isr_handler(void *arg) { + machine_pin_obj_t *self = arg; + mp_obj_t handler = MP_STATE_PORT(machine_pin_irq_handler)[self->id]; + mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self)); +} + +gpio_num_t machine_pin_get_id(mp_obj_t pin_in) { + if (mp_obj_get_type(pin_in) != &machine_pin_type) { + mp_raise_ValueError("expecting a pin"); + } + machine_pin_obj_t *self = pin_in; + return self->id; +} + +STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pin_obj_t *self = self_in; + mp_printf(print, "Pin(%u)", self->id); +} + +// pin.init(mode, pull=None, *, value) +STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_pull, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // configure the pin for gpio + gpio_pad_select_gpio(self->id); + + // set initial value (do this before configuring mode/pull) + if (args[ARG_value].u_obj != MP_OBJ_NULL) { + gpio_set_level(self->id, mp_obj_is_true(args[ARG_value].u_obj)); + } + + // configure mode + if (args[ARG_mode].u_obj != mp_const_none) { + mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj); + if (self->id >= 34 && (pin_io_mode & GPIO_MODE_DEF_OUTPUT)) { + mp_raise_ValueError("pin can only be input"); + } else { + gpio_set_direction(self->id, pin_io_mode); + } + } + + // configure pull + if (args[ARG_pull].u_obj != mp_const_none) { + gpio_set_pull_mode(self->id, mp_obj_get_int(args[ARG_pull].u_obj)); + } + + return mp_const_none; +} + +// constructor(id, ...) +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted pin object + int wanted_pin = mp_obj_get_int(args[0]); + const machine_pin_obj_t *self = NULL; + if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) { + self = (machine_pin_obj_t*)&machine_pin_obj[wanted_pin]; + } + if (self == NULL || self->base.type == NULL) { + mp_raise_ValueError("invalid pin"); + } + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(self); +} + +// fast method for getting/setting pin value +STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + machine_pin_obj_t *self = self_in; + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(gpio_get_level(self->id)); + } else { + // set pin + gpio_set_level(self->id, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +// pin.init(mode, pull) +STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); + +// pin.value([value]) +STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) { + return machine_pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value); + +// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING) +STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_handler, ARG_trigger, ARG_wake }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} }, + { MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (n_args > 1 || kw_args->used != 0) { + // configure irq + mp_obj_t handler = args[ARG_handler].u_obj; + uint32_t trigger = args[ARG_trigger].u_int; + mp_obj_t wake_obj = args[ARG_wake].u_obj; + + if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) { + mp_int_t wake; + if (mp_obj_get_int_maybe(wake_obj, &wake)) { + if (wake < 2 || wake > 7) { + mp_raise_ValueError("bad wake value"); + } + } else { + mp_raise_ValueError("bad wake value"); + } + + if (machine_rtc_config.wake_on_touch) { // not compatible + mp_raise_ValueError("no resources"); + } + + if (!RTC_IS_VALID_EXT_PIN(self->id)) { + mp_raise_ValueError("invalid pin for wake"); + } + + if (machine_rtc_config.ext0_pin == -1) { + machine_rtc_config.ext0_pin = self->id; + } else if (machine_rtc_config.ext0_pin != self->id) { + mp_raise_ValueError("no resources"); + } + + machine_rtc_config.ext0_level = trigger == GPIO_PIN_INTR_LOLEVEL ? 0 : 1; + machine_rtc_config.ext0_wake_types = wake; + } else { + if (machine_rtc_config.ext0_pin == self->id) { + machine_rtc_config.ext0_pin = -1; + } + + if (handler == mp_const_none) { + handler = MP_OBJ_NULL; + trigger = 0; + } + gpio_isr_handler_remove(self->id); + MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler; + gpio_set_intr_type(self->id, trigger); + gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self); + } + } + + // return the irq object + return MP_OBJ_FROM_PTR(&machine_pin_irq_object[self->id]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq); + +STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) }, + { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT) }, + { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT_OD) }, + { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP_ONLY) }, + { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN_ONLY) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) }, +}; + +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + machine_pin_obj_t *self = self_in; + + switch (request) { + case MP_PIN_READ: { + return gpio_get_level(self->id); + } + case MP_PIN_WRITE: { + gpio_set_level(self->id, arg); + return 0; + } + } + return -1; +} + +STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); + +STATIC const mp_pin_p_t pin_pin_p = { + .ioctl = pin_ioctl, +}; + +const mp_obj_type_t machine_pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = machine_pin_print, + .make_new = mp_pin_make_new, + .call = machine_pin_call, + .protocol = &pin_pin_p, + .locals_dict = (mp_obj_t)&machine_pin_locals_dict, +}; + +/******************************************************************************/ +// Pin IRQ object + +STATIC const mp_obj_type_t machine_pin_irq_type; + +STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = { + {{&machine_pin_irq_type}, GPIO_NUM_0}, + {{&machine_pin_irq_type}, GPIO_NUM_1}, + {{&machine_pin_irq_type}, GPIO_NUM_2}, + {{&machine_pin_irq_type}, GPIO_NUM_3}, + {{&machine_pin_irq_type}, GPIO_NUM_4}, + {{&machine_pin_irq_type}, GPIO_NUM_5}, + {{&machine_pin_irq_type}, GPIO_NUM_6}, + {{&machine_pin_irq_type}, GPIO_NUM_7}, + {{&machine_pin_irq_type}, GPIO_NUM_8}, + {{&machine_pin_irq_type}, GPIO_NUM_9}, + {{&machine_pin_irq_type}, GPIO_NUM_10}, + {{&machine_pin_irq_type}, GPIO_NUM_11}, + {{&machine_pin_irq_type}, GPIO_NUM_12}, + {{&machine_pin_irq_type}, GPIO_NUM_13}, + {{&machine_pin_irq_type}, GPIO_NUM_14}, + {{&machine_pin_irq_type}, GPIO_NUM_15}, + {{&machine_pin_irq_type}, GPIO_NUM_16}, + {{&machine_pin_irq_type}, GPIO_NUM_17}, + {{&machine_pin_irq_type}, GPIO_NUM_18}, + {{&machine_pin_irq_type}, GPIO_NUM_19}, + {{NULL}, -1}, + {{&machine_pin_irq_type}, GPIO_NUM_21}, + {{&machine_pin_irq_type}, GPIO_NUM_22}, + {{&machine_pin_irq_type}, GPIO_NUM_23}, + {{NULL}, -1}, + {{&machine_pin_irq_type}, GPIO_NUM_25}, + {{&machine_pin_irq_type}, GPIO_NUM_26}, + {{&machine_pin_irq_type}, GPIO_NUM_27}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{NULL}, -1}, + {{&machine_pin_irq_type}, GPIO_NUM_32}, + {{&machine_pin_irq_type}, GPIO_NUM_33}, + {{&machine_pin_irq_type}, GPIO_NUM_34}, + {{&machine_pin_irq_type}, GPIO_NUM_35}, + {{&machine_pin_irq_type}, GPIO_NUM_36}, + {{&machine_pin_irq_type}, GPIO_NUM_37}, + {{&machine_pin_irq_type}, GPIO_NUM_38}, + {{&machine_pin_irq_type}, GPIO_NUM_39}, +}; + +STATIC mp_obj_t machine_pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + machine_pin_irq_obj_t *self = self_in; + mp_arg_check_num(n_args, n_kw, 0, 0, false); + machine_pin_isr_handler((void*)&machine_pin_obj[self->id]); + return mp_const_none; +} + +STATIC mp_obj_t machine_pin_irq_trigger(size_t n_args, const mp_obj_t *args) { + machine_pin_irq_obj_t *self = args[0]; + uint32_t orig_trig = GPIO.pin[self->id].int_type; + if (n_args == 2) { + // set trigger + gpio_set_intr_type(self->id, mp_obj_get_int(args[1])); + } + // return original trigger value + return MP_OBJ_NEW_SMALL_INT(orig_trig); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_irq_trigger_obj, 1, 2, machine_pin_irq_trigger); + +STATIC const mp_rom_map_elem_t machine_pin_irq_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&machine_pin_irq_trigger_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_pin_irq_locals_dict, machine_pin_irq_locals_dict_table); + +STATIC const mp_obj_type_t machine_pin_irq_type = { + { &mp_type_type }, + .name = MP_QSTR_IRQ, + .call = machine_pin_irq_call, + .locals_dict = (mp_obj_dict_t*)&machine_pin_irq_locals_dict, +}; diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c new file mode 100644 index 0000000000..4d6c59f0fa --- /dev/null +++ b/ports/esp32/machine_pwm.c @@ -0,0 +1,277 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include "driver/ledc.h" +#include "esp_err.h" + +#include "py/nlr.h" +#include "py/runtime.h" +#include "modmachine.h" +#include "mphalport.h" + +// Forward dec'l +extern const mp_obj_type_t machine_pwm_type; + +typedef struct _esp32_pwm_obj_t { + mp_obj_base_t base; + gpio_num_t pin; + uint8_t active; + uint8_t channel; +} esp32_pwm_obj_t; + +// Which channel has which GPIO pin assigned? +// (-1 if not assigned) +STATIC int chan_gpio[LEDC_CHANNEL_MAX]; + +// Params for PW operation +// 5khz +#define PWFREQ (5000) +// High speed mode +#define PWMODE (LEDC_HIGH_SPEED_MODE) +// 10-bit resolution (compatible with esp8266 PWM) +#define PWRES (LEDC_TIMER_10_BIT) +// Timer 1 +#define PWTIMER (LEDC_TIMER_1) + +// Config of timer upon which we run all PWM'ed GPIO pins +STATIC bool pwm_inited = false; +STATIC ledc_timer_config_t timer_cfg = { + .bit_num = PWRES, + .freq_hz = PWFREQ, + .speed_mode = PWMODE, + .timer_num = PWTIMER +}; + +STATIC void pwm_init(void) { + + // Initial condition: no channels assigned + for (int x = 0; x < LEDC_CHANNEL_MAX; ++x) { + chan_gpio[x] = -1; + } + + // Init with default timer params + ledc_timer_config(&timer_cfg); +} + +STATIC int set_freq(int newval) { + int oval = timer_cfg.freq_hz; + + timer_cfg.freq_hz = newval; + if (ledc_timer_config(&timer_cfg) != ESP_OK) { + timer_cfg.freq_hz = oval; + return 0; + } + return 1; +} + +/******************************************************************************/ + +// MicroPython bindings for PWM + +STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "PWM(%u", self->pin); + if (self->active) { + mp_printf(print, ", freq=%u, duty=%u", timer_cfg.freq_hz, + ledc_get_duty(PWMODE, self->channel)); + } + mp_printf(print, ")"); +} + +STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, + size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_freq, ARG_duty }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int channel; + int avail = -1; + + // Find a free PWM channel, also spot if our pin is + // already mentioned. + for (channel = 0; channel < LEDC_CHANNEL_MAX; ++channel) { + if (chan_gpio[channel] == self->pin) { + break; + } + if ((avail == -1) && (chan_gpio[channel] == -1)) { + avail = channel; + } + } + if (channel >= LEDC_CHANNEL_MAX) { + if (avail == -1) { + mp_raise_ValueError("out of PWM channels"); + } + channel = avail; + } + self->channel = channel; + + // New PWM assignment + self->active = 1; + if (chan_gpio[channel] == -1) { + ledc_channel_config_t cfg = { + .channel = channel, + .duty = (1 << PWRES) / 2, + .gpio_num = self->pin, + .intr_type = LEDC_INTR_DISABLE, + .speed_mode = PWMODE, + .timer_sel = PWTIMER, + }; + if (ledc_channel_config(&cfg) != ESP_OK) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "PWM not supported on pin %d", self->pin)); + } + chan_gpio[channel] = self->pin; + } + + // Maybe change PWM timer + int tval = args[ARG_freq].u_int; + if (tval != -1) { + if (tval != timer_cfg.freq_hz) { + if (!set_freq(tval)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Bad frequency %d", tval)); + } + } + } + + // Set duty cycle? + int dval = args[ARG_duty].u_int; + if (dval != -1) { + dval &= ((1 << PWRES)-1); + ledc_set_duty(PWMODE, channel, dval); + ledc_update_duty(PWMODE, channel); + } +} + +STATIC mp_obj_t esp32_pwm_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + + // create PWM object from the given pin + esp32_pwm_obj_t *self = m_new_obj(esp32_pwm_obj_t); + self->base.type = &machine_pwm_type; + self->pin = pin_id; + self->active = 0; + self->channel = -1; + + // start the PWM subsystem if it's not already running + if (!pwm_inited) { + pwm_init(); + pwm_inited = true; + } + + // start the PWM running for this channel + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + esp32_pwm_init_helper(self, n_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t esp32_pwm_init(size_t n_args, + const mp_obj_t *args, mp_map_t *kw_args) { + esp32_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(esp32_pwm_init_obj, 1, esp32_pwm_init); + +STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); + int chan = self->channel; + + // Valid channel? + if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) { + // Mark it unused, and tell the hardware to stop routing + chan_gpio[chan] = -1; + ledc_stop(PWMODE, chan, 0); + self->active = 0; + self->channel = -1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_pwm_deinit_obj, esp32_pwm_deinit); + +STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // get + return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz); + } + + // set + int tval = mp_obj_get_int(args[1]); + if (!set_freq(tval)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Bad frequency %d", tval)); + } + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_freq_obj, 1, 2, esp32_pwm_freq); + +STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); + int duty; + + if (n_args == 1) { + // get + duty = ledc_get_duty(PWMODE, self->channel); + return MP_OBJ_NEW_SMALL_INT(duty); + } + + // set + duty = mp_obj_get_int(args[1]); + duty &= ((1 << PWRES)-1); + ledc_set_duty(PWMODE, self->channel, duty); + ledc_update_duty(PWMODE, self->channel); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_duty_obj, + 1, 2, esp32_pwm_duty); + +STATIC const mp_rom_map_elem_t esp32_pwm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp32_pwm_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_pwm_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&esp32_pwm_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&esp32_pwm_duty_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp32_pwm_locals_dict, + esp32_pwm_locals_dict_table); + +const mp_obj_type_t machine_pwm_type = { + { &mp_type_type }, + .name = MP_QSTR_PWM, + .print = esp32_pwm_print, + .make_new = esp32_pwm_make_new, + .locals_dict = (mp_obj_dict_t*)&esp32_pwm_locals_dict, +}; diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c new file mode 100644 index 0000000000..b17932da5c --- /dev/null +++ b/ports/esp32/machine_rtc.c @@ -0,0 +1,162 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * Copyright (c) 2017 "Tom Manning" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include +#include +#include "driver/gpio.h" + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "timeutils.h" +#include "modmachine.h" +#include "machine_rtc.h" + +typedef struct _machine_rtc_obj_t { + mp_obj_base_t base; +} machine_rtc_obj_t; + +#define MEM_MAGIC 0x75507921 +/* There is 8K of rtc_slow_memory, but some is used by the system software + If the USER_MAXLEN is set to high, the following compile error will happen: + region `rtc_slow_seg' overflowed by N bytes + The current system software allows almost 4096 to be used. + To avoid running into issues if the system software uses more, 2048 was picked as a max length +*/ +#define MEM_USER_MAXLEN 2048 +RTC_DATA_ATTR uint32_t rtc_user_mem_magic; +RTC_DATA_ATTR uint32_t rtc_user_mem_len; +RTC_DATA_ATTR uint8_t rtc_user_mem_data[MEM_USER_MAXLEN]; + +// singleton RTC object +STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}}; + +machine_rtc_config_t machine_rtc_config = { + .ext1_pins = 0, + .ext0_pin = -1 + }; + +STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&machine_rtc_obj; +} + +STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // Get time + + struct timeval tv; + + gettimeofday(&tv, NULL); + timeutils_struct_time_t tm; + + timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); + + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(tv.tv_usec) + }; + + return mp_obj_new_tuple(8, tuple); + } else { + // Set time + + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 8, &items); + + struct timeval tv = {0}; + tv.tv_sec = timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6])); + settimeofday(&tv, NULL); + + return mp_const_none; + } +} +STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { + return machine_rtc_datetime_helper(n_args, args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime); + +STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) { + mp_obj_t args[2] = {self_in, date}; + machine_rtc_datetime_helper(2, args); + + if (rtc_user_mem_magic != MEM_MAGIC) { + rtc_user_mem_magic = MEM_MAGIC; + rtc_user_mem_len = 0; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init); + +STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // read RTC memory + uint32_t len = rtc_user_mem_len; + uint8_t rtcram[MEM_USER_MAXLEN]; + memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len); + return mp_obj_new_bytes(rtcram, len); + } else { + // write RTC memory + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + if (bufinfo.len > MEM_USER_MAXLEN) { + mp_raise_ValueError("buffer too long"); + } + memcpy( (char *) rtc_user_mem_data, (char *) bufinfo.buf, bufinfo.len); + rtc_user_mem_len = bufinfo.len; + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_memory_obj, 1, 2, machine_rtc_memory); + +STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_datetime_obj) }, + { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) }, + { MP_ROM_QSTR(MP_QSTR_memory), MP_ROM_PTR(&machine_rtc_memory_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table); + +const mp_obj_type_t machine_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .make_new = machine_rtc_make_new, + .locals_dict = (mp_obj_t)&machine_rtc_locals_dict, +}; diff --git a/ports/esp32/machine_rtc.h b/ports/esp32/machine_rtc.h new file mode 100644 index 0000000000..e34deb9be6 --- /dev/null +++ b/ports/esp32/machine_rtc.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * Copyright (c) 2017 "Tom Manning" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ESP32_MACHINE_RTC_H +#define MICROPY_INCLUDED_ESP32_MACHINE_RTC_H + +#include "modmachine.h" + +typedef struct { + uint64_t ext1_pins; // set bit == pin# + int8_t ext0_pin; // just the pin#, -1 == None + bool wake_on_touch : 1; + bool ext0_level : 1; + wake_type_t ext0_wake_types; + bool ext1_level : 1; +} machine_rtc_config_t; + +extern machine_rtc_config_t machine_rtc_config; + +#endif diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c new file mode 100644 index 0000000000..235a502bd3 --- /dev/null +++ b/ports/esp32/machine_timer.c @@ -0,0 +1,192 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "driver/timer.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "modmachine.h" + +#define TIMER_INTR_SEL TIMER_INTR_LEVEL +#define TIMER_DIVIDER 40000 +#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) + +#define TIMER_FLAGS 0 + +typedef struct _machine_timer_obj_t { + mp_obj_base_t base; + mp_uint_t group; + mp_uint_t index; + + mp_uint_t repeat; + mp_uint_t period; + + mp_obj_t callback; + + intr_handle_t handle; +} machine_timer_obj_t; + +const mp_obj_type_t machine_timer_type; + +STATIC esp_err_t check_esp_err(esp_err_t code) { + if (code) { + mp_raise_OSError(code); + } + + return code; +} + +STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_timer_obj_t *self = self_in; + + timer_config_t config; + mp_printf(print, "Timer(%p; ", self); + + timer_get_config(self->group, self->index, &config); + + mp_printf(print, "alarm_en=%d, ", config.alarm_en); + mp_printf(print, "auto_reload=%d, ", config.auto_reload); + mp_printf(print, "counter_en=%d)", config.counter_en); +} + +STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t); + self->base.type = &machine_timer_type; + + self->group = (mp_obj_get_int(args[0]) >> 1) & 1; + self->index = mp_obj_get_int(args[0]) & 1; + + return self; +} + +STATIC void machine_timer_disable(machine_timer_obj_t *self) { + if (self->handle) { + timer_pause(self->group, self->index); + esp_intr_free(self->handle); + self->handle = NULL; + } +} + +STATIC void machine_timer_isr(void *self_in) { + machine_timer_obj_t *self = self_in; + timg_dev_t *device = self->group ? &(TIMERG1) : &(TIMERG0); + + device->hw_timer[self->index].update = 1; + if (self->index) { + device->int_clr_timers.t1 = 1; + } else { + device->int_clr_timers.t0 = 1; + } + device->hw_timer[self->index].config.alarm_en = self->repeat; + + mp_sched_schedule(self->callback, self); +} + +STATIC void machine_timer_enable(machine_timer_obj_t *self) { + timer_config_t config; + config.alarm_en = TIMER_ALARM_EN; + config.auto_reload = self->repeat; + config.counter_dir = TIMER_COUNT_UP; + config.divider = TIMER_DIVIDER; + config.intr_type = TIMER_INTR_LEVEL; + config.counter_en = TIMER_PAUSE; + + check_esp_err(timer_init(self->group, self->index, &config)); + check_esp_err(timer_set_counter_value(self->group, self->index, 0x00000000)); + check_esp_err(timer_set_alarm_value(self->group, self->index, self->period)); + check_esp_err(timer_enable_intr(self->group, self->index)); + check_esp_err(timer_isr_register(self->group, self->index, machine_timer_isr, (void*)self, TIMER_FLAGS, &self->handle)); + check_esp_err(timer_start(self->group, self->index)); +} + +STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + machine_timer_disable(self); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Timer uses an 80MHz base clock, which is divided by the divider/scalar, we then convert to ms. + self->period = (args[0].u_int * TIMER_BASE_CLK) / (1000 * TIMER_DIVIDER); + self->repeat = args[1].u_int; + self->callback = args[2].u_obj; + self->handle = NULL; + + machine_timer_enable(self); + + return mp_const_none; +} + +STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) { + machine_timer_disable(self_in); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit); + +STATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init); + +STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) { + machine_timer_obj_t *self = self_in; + double result; + + timer_get_counter_time_sec(self->group, self->index, &result); + + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value); + +STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_timer_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) }, + { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table); + +const mp_obj_type_t machine_timer_type = { + { &mp_type_type }, + .name = MP_QSTR_Timer, + .print = machine_timer_print, + .make_new = machine_timer_make_new, + .locals_dict = (mp_obj_t)&machine_timer_locals_dict, +}; diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c new file mode 100644 index 0000000000..96de1a2a1d --- /dev/null +++ b/ports/esp32/machine_touchpad.c @@ -0,0 +1,110 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Nick Moore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "esp_log.h" + +#include "driver/gpio.h" +#include "driver/touch_pad.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "modmachine.h" + +typedef struct _mtp_obj_t { + mp_obj_base_t base; + gpio_num_t gpio_id; + touch_pad_t touchpad_id; +} mtp_obj_t; + +STATIC const mtp_obj_t touchpad_obj[] = { + {{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_NUM0}, + {{&machine_touchpad_type}, GPIO_NUM_0, TOUCH_PAD_NUM1}, + {{&machine_touchpad_type}, GPIO_NUM_2, TOUCH_PAD_NUM2}, + {{&machine_touchpad_type}, GPIO_NUM_15, TOUCH_PAD_NUM3}, + {{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM4}, + {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM5}, + {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM6}, + {{&machine_touchpad_type}, GPIO_NUM_27, TOUCH_PAD_NUM7}, + {{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM8}, + {{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM9}, +}; + +STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, + const mp_obj_t *args) { + + mp_arg_check_num(n_args, n_kw, 1, 1, true); + gpio_num_t pin_id = machine_pin_get_id(args[0]); + const mtp_obj_t *self = NULL; + for (int i = 0; i < MP_ARRAY_SIZE(touchpad_obj); i++) { + if (pin_id == touchpad_obj[i].gpio_id) { self = &touchpad_obj[i]; break; } + } + if (!self) mp_raise_ValueError("invalid pin for touchpad"); + + static int initialized = 0; + if (!initialized) { + touch_pad_init(); + initialized = 1; + } + esp_err_t err = touch_pad_config(self->touchpad_id, 0); + if (err == ESP_OK) return MP_OBJ_FROM_PTR(self); + mp_raise_ValueError("Touch pad error"); +} + +STATIC mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) { + mtp_obj_t *self = self_in; + uint16_t value = mp_obj_get_int(value_in); + esp_err_t err = touch_pad_config(self->touchpad_id, value); + if (err == ESP_OK) return mp_const_none; + mp_raise_ValueError("Touch pad error"); +} +MP_DEFINE_CONST_FUN_OBJ_2(mtp_config_obj, mtp_config); + +STATIC mp_obj_t mtp_read(mp_obj_t self_in) { + mtp_obj_t *self = self_in; + uint16_t value; + esp_err_t err = touch_pad_read(self->touchpad_id, &value); + if (err == ESP_OK) return MP_OBJ_NEW_SMALL_INT(value); + mp_raise_ValueError("Touch pad error"); +} +MP_DEFINE_CONST_FUN_OBJ_1(mtp_read_obj, mtp_read); + +STATIC const mp_rom_map_elem_t mtp_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&mtp_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mtp_read_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mtp_locals_dict, mtp_locals_dict_table); + +const mp_obj_type_t machine_touchpad_type = { + { &mp_type_type }, + .name = MP_QSTR_TouchPad, + .make_new = mtp_make_new, + .locals_dict = (mp_obj_t)&mtp_locals_dict, +}; diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c new file mode 100644 index 0000000000..474764b1b6 --- /dev/null +++ b/ports/esp32/machine_uart.c @@ -0,0 +1,357 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "driver/uart.h" +#include "freertos/FreeRTOS.h" + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "modmachine.h" + +typedef struct _machine_uart_obj_t { + mp_obj_base_t base; + uart_port_t uart_num; + uint8_t bits; + uint8_t parity; + uint8_t stop; + int8_t tx; + int8_t rx; + int8_t rts; + int8_t cts; + uint16_t timeout; // timeout waiting for first char (in ms) + uint16_t timeout_char; // timeout waiting between chars (in ms) +} machine_uart_obj_t; + +STATIC const char *_parity_name[] = {"None", "1", "0"}; + +/******************************************************************************/ +// MicroPython bindings for UART + +STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t baudrate; + uart_get_baudrate(self->uart_num, &baudrate); + mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, rts=%d, cts=%d, timeout=%u, timeout_char=%u)", + self->uart_num, baudrate, self->bits, _parity_name[self->parity], + self->stop, self->tx, self->rx, self->rts, self->cts, self->timeout, self->timeout_char); +} + +STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_timeout, ARG_timeout_char }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // wait for all data to be transmitted before changing settings + uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000)); + + // set baudrate + uint32_t baudrate = 115200; + if (args[ARG_baudrate].u_int > 0) { + uart_set_baudrate(self->uart_num, args[ARG_baudrate].u_int); + uart_get_baudrate(self->uart_num, &baudrate); + } + + uart_set_pin(self->uart_num, args[ARG_tx].u_int, args[ARG_rx].u_int, args[ARG_rts].u_int, args[ARG_cts].u_int); + if (args[ARG_tx].u_int != UART_PIN_NO_CHANGE) { + self->tx = args[ARG_tx].u_int; + } + + if (args[ARG_rx].u_int != UART_PIN_NO_CHANGE) { + self->rx = args[ARG_rx].u_int; + } + + if (args[ARG_rts].u_int != UART_PIN_NO_CHANGE) { + self->rts = args[ARG_rts].u_int; + } + + if (args[ARG_cts].u_int != UART_PIN_NO_CHANGE) { + self->cts = args[ARG_cts].u_int; + } + + // set data bits + switch (args[ARG_bits].u_int) { + case 0: + break; + case 5: + uart_set_word_length(self->uart_num, UART_DATA_5_BITS); + self->bits = 5; + break; + case 6: + uart_set_word_length(self->uart_num, UART_DATA_6_BITS); + self->bits = 6; + break; + case 7: + uart_set_word_length(self->uart_num, UART_DATA_7_BITS); + self->bits = 7; + break; + case 8: + uart_set_word_length(self->uart_num, UART_DATA_8_BITS); + self->bits = 8; + break; + default: + mp_raise_ValueError("invalid data bits"); + break; + } + + // set parity + if (args[ARG_parity].u_obj != MP_OBJ_NULL) { + if (args[ARG_parity].u_obj == mp_const_none) { + uart_set_parity(self->uart_num, UART_PARITY_DISABLE); + self->parity = 0; + } else { + mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj); + if (parity & 1) { + uart_set_parity(self->uart_num, UART_PARITY_ODD); + self->parity = 1; + } else { + uart_set_parity(self->uart_num, UART_PARITY_EVEN); + self->parity = 2; + } + } + } + + // set stop bits + switch (args[ARG_stop].u_int) { + // FIXME: ESP32 also supports 1.5 stop bits + case 0: + break; + case 1: + uart_set_stop_bits(self->uart_num, UART_STOP_BITS_1); + self->stop = 1; + break; + case 2: + uart_set_stop_bits(self->uart_num, UART_STOP_BITS_2); + self->stop = 2; + break; + default: + mp_raise_ValueError("invalid stop bits"); + break; + } + + // set timeout + self->timeout = args[ARG_timeout].u_int; + + // set timeout_char + // make sure it is at least as long as a whole character (13 bits to be safe) + self->timeout_char = args[ARG_timeout_char].u_int; + uint32_t min_timeout_char = 13000 / baudrate + 1; + if (self->timeout_char < min_timeout_char) { + self->timeout_char = min_timeout_char; + } +} + +STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get uart id + mp_int_t uart_num = mp_obj_get_int(args[0]); + if (uart_num < 0 || uart_num >= UART_NUM_MAX) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_num)); + } + + // Attempts to use UART0 from Python has resulted in all sorts of fun errors. + // FIXME: UART0 is disabled for now. + if (uart_num == UART_NUM_0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) is disabled (dedicated to REPL)", uart_num)); + } + + // Defaults + uart_config_t uartcfg = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 0 + }; + + // create instance + machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t); + self->base.type = &machine_uart_type; + self->uart_num = uart_num; + self->bits = 8; + self->parity = 0; + self->stop = 1; + self->rts = UART_PIN_NO_CHANGE; + self->cts = UART_PIN_NO_CHANGE; + self->timeout = 0; + self->timeout_char = 0; + + switch (uart_num) { + case UART_NUM_0: + self->rx = UART_PIN_NO_CHANGE; // GPIO 3 + self->tx = UART_PIN_NO_CHANGE; // GPIO 1 + break; + case UART_NUM_1: + self->rx = 9; + self->tx = 10; + break; + case UART_NUM_2: + self->rx = 16; + self->tx = 17; + break; + } + + // Remove any existing configuration + uart_driver_delete(self->uart_num); + + // init the peripheral + // Setup + uart_param_config(self->uart_num, &uartcfg); + + // RX and TX buffers are currently hardcoded at 256 bytes each (IDF minimum). + uart_driver_install(uart_num, 256, 256, 0, NULL, 0); + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args); + + // Make sure pins are connected. + uart_set_pin(self->uart_num, self->tx, self->rx, self->rts, self->cts); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + machine_uart_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init); + +STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t rxbufsize; + uart_get_buffered_data_len(self->uart_num, &rxbufsize); + return MP_OBJ_NEW_SMALL_INT(rxbufsize); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any); + +STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) }, + + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table); + +STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + TickType_t time_to_wait; + if (self->timeout == 0) { + time_to_wait = 0; + } else { + time_to_wait = pdMS_TO_TICKS(self->timeout); + } + + int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait); + + if (bytes_read <= 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + return bytes_read; +} + +STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + + int bytes_written = uart_write_bytes(self->uart_num, buf_in, size); + + if (bytes_written < 0) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + + // return number of bytes written + return bytes_written; +} + +STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + machine_uart_obj_t *self = self_in; + mp_uint_t ret; + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + size_t rxbufsize; + uart_get_buffered_data_len(self->uart_num, &rxbufsize); + if ((flags & MP_STREAM_POLL_RD) && rxbufsize > 0) { + ret |= MP_STREAM_POLL_RD; + } + if ((flags & MP_STREAM_POLL_WR) && 1) { // FIXME: uart_tx_any_room(self->uart_num) + ret |= MP_STREAM_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +STATIC const mp_stream_p_t uart_stream_p = { + .read = machine_uart_read, + .write = machine_uart_write, + .ioctl = machine_uart_ioctl, + .is_text = false, +}; + +const mp_obj_type_t machine_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = machine_uart_print, + .make_new = machine_uart_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_dict_t*)&machine_uart_locals_dict, +}; diff --git a/ports/esp32/machine_wdt.c b/ports/esp32/machine_wdt.c new file mode 100644 index 0000000000..88a58f056a --- /dev/null +++ b/ports/esp32/machine_wdt.c @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2017 Eric Poulsen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" + +#include "esp_task_wdt.h" + +const mp_obj_type_t machine_wdt_type; + +typedef struct _machine_wdt_obj_t { + mp_obj_base_t base; +} machine_wdt_obj_t; + +STATIC machine_wdt_obj_t wdt_default = {{&machine_wdt_type}}; + +STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + mp_int_t id = 0; + if (n_args > 0) { + id = mp_obj_get_int(args[0]); + } + + switch (id) { + case 0: + esp_task_wdt_add(NULL); + return &wdt_default; + default: + mp_raise_ValueError(NULL); + } +} + +STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { + (void)self_in; + esp_task_wdt_reset(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); + +STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table); + +const mp_obj_type_t machine_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = machine_wdt_make_new, + .locals_dict = (mp_obj_t)&machine_wdt_locals_dict, +}; diff --git a/ports/esp32/main.c b/ports/esp32/main.c new file mode 100644 index 0000000000..acbbfdccce --- /dev/null +++ b/ports/esp32/main.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_task.h" +#include "soc/cpu.h" +#include "esp_log.h" + +#include "py/stackctrl.h" +#include "py/nlr.h" +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "lib/mp-readline/readline.h" +#include "lib/utils/pyexec.h" +#include "uart.h" +#include "modmachine.h" +#include "modnetwork.h" +#include "mpthreadport.h" + +// MicroPython runs as a task under FreeRTOS +#define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1) +#define MP_TASK_STACK_SIZE (16 * 1024) +#define MP_TASK_STACK_LEN (MP_TASK_STACK_SIZE / sizeof(StackType_t)) + +STATIC StaticTask_t mp_task_tcb; +STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8))); + +int vprintf_null(const char *format, va_list ap) { + // do nothing: this is used as a log target during raw repl mode + return 0; +} + +void mp_task(void *pvParameter) { + volatile uint32_t sp = (uint32_t)get_sp(); + #if MICROPY_PY_THREAD + mp_thread_init(&mp_task_stack[0], MP_TASK_STACK_LEN); + #endif + uart_init(); + + // Allocate the uPy heap using malloc and get the largest available region + size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + void *mp_task_heap = malloc(mp_task_heap_size); + +soft_reset: + // initialise the stack pointer for the main thread + mp_stack_set_top((void *)sp); + mp_stack_set_limit(MP_TASK_STACK_SIZE - 1024); + gc_init(mp_task_heap, mp_task_heap + 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 + machine_pins_init(); + + // run boot-up scripts + pyexec_frozen_module("_boot.py"); + pyexec_file("boot.py"); + if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { + pyexec_file("main.py"); + } + + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null); + if (pyexec_raw_repl() != 0) { + break; + } + esp_log_set_vprintf(vprintf_log); + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } + + #if MICROPY_PY_THREAD + mp_thread_deinit(); + #endif + + gc_sweep_all(); + + mp_hal_stdout_tx_str("PYB: soft reboot\r\n"); + + // deinitialise peripherals + machine_pins_deinit(); + usocket_events_deinit(); + + mp_deinit(); + fflush(stdout); + goto soft_reset; +} + +void app_main(void) { + nvs_flash_init(); + xTaskCreateStaticPinnedToCore(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY, + &mp_task_stack[0], &mp_task_tcb, 0); +} + +void nlr_jump_fail(void *val) { + printf("NLR jump failed, val=%p\n", val); + esp_restart(); +} + +// modussl_mbedtls uses this function but it's not enabled in ESP IDF +void mbedtls_debug_set_threshold(int threshold) { + (void)threshold; +} diff --git a/ports/esp32/makeimg.py b/ports/esp32/makeimg.py new file mode 100644 index 0000000000..aeedbff7ef --- /dev/null +++ b/ports/esp32/makeimg.py @@ -0,0 +1,25 @@ +import sys + +OFFSET_BOOTLOADER = 0x1000 +OFFSET_PARTITIONS = 0x8000 +OFFSET_APPLICATION = 0x10000 + +files_in = [ + ('bootloader', OFFSET_BOOTLOADER, sys.argv[1]), + ('partitions', OFFSET_PARTITIONS, sys.argv[2]), + ('application', OFFSET_APPLICATION, sys.argv[3]), +] +file_out = sys.argv[4] + +cur_offset = OFFSET_BOOTLOADER +with open(file_out, 'wb') as fout: + for name, offset, file_in in files_in: + assert offset >= cur_offset + fout.write(b'\xff' * (offset - cur_offset)) + cur_offset = offset + with open(file_in, 'rb') as fin: + data = fin.read() + fout.write(data) + cur_offset += len(data) + print('%-12s% 8d' % (name, len(data))) + print('%-12s% 8d' % ('total', cur_offset)) diff --git a/ports/esp32/memory.h b/ports/esp32/memory.h new file mode 100644 index 0000000000..f3777b0e39 --- /dev/null +++ b/ports/esp32/memory.h @@ -0,0 +1,2 @@ +// this is needed for extmod/crypto-algorithms/sha256.c +#include diff --git a/ports/esp32/modesp.c b/ports/esp32/modesp.c new file mode 100644 index 0000000000..e614f77a6a --- /dev/null +++ b/ports/esp32/modesp.c @@ -0,0 +1,157 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Paul Sokolovsky + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "rom/gpio.h" +#include "esp_log.h" +#include "esp_spi_flash.h" + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "drivers/dht/dht.h" +#include "modesp.h" + +STATIC mp_obj_t esp_osdebug(size_t n_args, const mp_obj_t *args) { + esp_log_level_t level = LOG_LOCAL_LEVEL; + if (n_args == 2) { + level = mp_obj_get_int(args[1]); + } + if (args[0] == mp_const_none) { + // Disable logging + esp_log_level_set("*", ESP_LOG_ERROR); + } else { + // Enable logging at the given level + // TODO args[0] should set the UART to which debug is sent + esp_log_level_set("*", level); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_osdebug_obj, 1, 2, esp_osdebug); + +STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t buf_in) { + mp_int_t offset = mp_obj_get_int(offset_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + esp_err_t res = spi_flash_read(offset, bufinfo.buf, bufinfo.len); + if (res != ESP_OK) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read); + +STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, mp_obj_t buf_in) { + mp_int_t offset = mp_obj_get_int(offset_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + esp_err_t res = spi_flash_write(offset, bufinfo.buf, bufinfo.len); + if (res != ESP_OK) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write); + +STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) { + mp_int_t sector = mp_obj_get_int(sector_in); + esp_err_t res = spi_flash_erase_sector(sector); + if (res != ESP_OK) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase); + +STATIC mp_obj_t esp_flash_size(void) { + return mp_obj_new_int_from_uint(spi_flash_get_chip_size()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size); + +STATIC mp_obj_t esp_flash_user_start(void) { + return MP_OBJ_NEW_SMALL_INT(0x200000); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start); + +STATIC mp_obj_t esp_gpio_matrix_in(mp_obj_t pin, mp_obj_t sig, mp_obj_t inv) { + gpio_matrix_in(mp_obj_get_int(pin), mp_obj_get_int(sig), mp_obj_get_int(inv)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_gpio_matrix_in_obj, esp_gpio_matrix_in); + +STATIC mp_obj_t esp_gpio_matrix_out(size_t n_args, const mp_obj_t *args) { + (void)n_args; + gpio_matrix_out(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_gpio_matrix_out_obj, 4, 4, esp_gpio_matrix_out); + +STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t timing) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + esp_neopixel_write(mp_hal_get_pin_obj(pin), + (uint8_t*)bufinfo.buf, bufinfo.len, mp_obj_get_int(timing)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_); + +STATIC const mp_rom_map_elem_t esp_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) }, + + { MP_ROM_QSTR(MP_QSTR_osdebug), MP_ROM_PTR(&esp_osdebug_obj) }, + + { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&esp_flash_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&esp_flash_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) }, + + { MP_ROM_QSTR(MP_QSTR_gpio_matrix_in), MP_ROM_PTR(&esp_gpio_matrix_in_obj) }, + { MP_ROM_QSTR(MP_QSTR_gpio_matrix_out), MP_ROM_PTR(&esp_gpio_matrix_out_obj) }, + + { MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, + + // Constants for second arg of osdebug() + { MP_ROM_QSTR(MP_QSTR_LOG_NONE), MP_ROM_INT((mp_uint_t)ESP_LOG_NONE)}, + { MP_ROM_QSTR(MP_QSTR_LOG_ERROR), MP_ROM_INT((mp_uint_t)ESP_LOG_ERROR)}, + { MP_ROM_QSTR(MP_QSTR_LOG_WARNING), MP_ROM_INT((mp_uint_t)ESP_LOG_WARN)}, + { MP_ROM_QSTR(MP_QSTR_LOG_INFO), MP_ROM_INT((mp_uint_t)ESP_LOG_INFO)}, + { MP_ROM_QSTR(MP_QSTR_LOG_DEBUG), MP_ROM_INT((mp_uint_t)ESP_LOG_DEBUG)}, + { MP_ROM_QSTR(MP_QSTR_LOG_VERBOSE), MP_ROM_INT((mp_uint_t)ESP_LOG_VERBOSE)}, +}; + +STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table); + +const mp_obj_module_t esp_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp_module_globals, +}; + diff --git a/ports/esp32/modesp.h b/ports/esp32/modesp.h new file mode 100644 index 0000000000..a822c02ecc --- /dev/null +++ b/ports/esp32/modesp.h @@ -0,0 +1 @@ +void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing); diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c new file mode 100644 index 0000000000..bab78e9543 --- /dev/null +++ b/ports/esp32/modesp32.c @@ -0,0 +1,141 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include +#include +#include "driver/gpio.h" + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "timeutils.h" +#include "modmachine.h" +#include "machine_rtc.h" +#include "modesp32.h" + +STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) { + + if (machine_rtc_config.ext0_pin != -1) { + mp_raise_ValueError("no resources"); + } + //nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "touchpad wakeup not available for this version of ESP-IDF")); + + machine_rtc_config.wake_on_touch = mp_obj_is_true(wake); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_wake_on_touch_obj, esp32_wake_on_touch); + +STATIC mp_obj_t esp32_wake_on_ext0(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + if (machine_rtc_config.wake_on_touch) { + mp_raise_ValueError("no resources"); + } + enum {ARG_pin, ARG_level}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = mp_obj_new_int(machine_rtc_config.ext0_pin)} }, + { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext0_level} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_pin].u_obj == mp_const_none) { + machine_rtc_config.ext0_pin = -1; // "None" + } else { + gpio_num_t pin_id = machine_pin_get_id(args[ARG_pin].u_obj); + if (pin_id != machine_rtc_config.ext0_pin) { + if (!RTC_IS_VALID_EXT_PIN(pin_id)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin")); + } + machine_rtc_config.ext0_pin = pin_id; + } + } + + machine_rtc_config.ext0_level = args[ARG_level].u_bool; + machine_rtc_config.ext0_wake_types = MACHINE_WAKE_SLEEP | MACHINE_WAKE_DEEPSLEEP; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext0_obj, 0, esp32_wake_on_ext0); + +STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum {ARG_pins, ARG_level}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext1_level} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint64_t ext1_pins = machine_rtc_config.ext1_pins; + + + // Check that all pins are allowed + if (args[ARG_pins].u_obj != mp_const_none) { + mp_uint_t len = 0; + mp_obj_t *elem; + mp_obj_get_array(args[ARG_pins].u_obj, &len, &elem); + ext1_pins = 0; + + for (int i = 0; i < len; i++) { + + gpio_num_t pin_id = machine_pin_get_id(elem[i]); + if (!RTC_IS_VALID_EXT_PIN(pin_id)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin")); + break; + } + ext1_pins |= (1ll << pin_id); + } + } + + machine_rtc_config.ext1_level = args[ARG_level].u_bool; + machine_rtc_config.ext1_pins = ext1_pins; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext1_obj, 0, esp32_wake_on_ext1); + +STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_touch), (mp_obj_t)&esp32_wake_on_touch_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext0), (mp_obj_t)&esp32_wake_on_ext0_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext1), (mp_obj_t)&esp32_wake_on_ext1_obj }, + + { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ALL_LOW), mp_const_false }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), mp_const_true }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp32_module_globals, esp32_module_globals_table); + +const mp_obj_module_t esp32_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp32_module_globals, +}; diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h new file mode 100644 index 0000000000..1d18cb41fb --- /dev/null +++ b/ports/esp32/modesp32.h @@ -0,0 +1,31 @@ +#ifndef MICROPY_INCLUDED_ESP32_MODESP32_H +#define MICROPY_INCLUDED_ESP32_MODESP32_H + +#define RTC_VALID_EXT_PINS \ +( \ + (1ll << 0) | \ + (1ll << 2) | \ + (1ll << 4) | \ + (1ll << 12) | \ + (1ll << 13) | \ + (1ll << 14) | \ + (1ll << 15) | \ + (1ll << 25) | \ + (1ll << 26) | \ + (1ll << 27) | \ + (1ll << 32) | \ + (1ll << 33) | \ + (1ll << 34) | \ + (1ll << 35) | \ + (1ll << 36) | \ + (1ll << 37) | \ + (1ll << 38) | \ + (1ll << 39) \ +) + +#define RTC_LAST_EXT_PIN 39 +#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) + +extern const mp_obj_type_t esp32_ulp_type; + +#endif // MICROPY_INCLUDED_ESP32_MODESP32_H diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c new file mode 100644 index 0000000000..2d59e137ef --- /dev/null +++ b/ports/esp32/modmachine.c @@ -0,0 +1,269 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "rom/ets_sys.h" +#include "rom/rtc.h" +#include "esp_system.h" +#include "driver/touch_pad.h" + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/machine_mem.h" +#include "extmod/machine_signal.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "extmod/machine_spi.h" +#include "modmachine.h" +#include "machine_rtc.h" + +#if MICROPY_PY_MACHINE + +typedef enum { + MP_PWRON_RESET = 1, + MP_HARD_RESET, + MP_WDT_RESET, + MP_DEEPSLEEP_RESET, + MP_SOFT_RESET +} reset_reason_t; + +STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // get + return mp_obj_new_int(ets_get_cpu_frequency() * 1000000); + } else { + // set + mp_int_t freq = mp_obj_get_int(args[0]) / 1000000; + if (freq != 80 && freq != 160 && freq != 240) { + mp_raise_ValueError("frequency can only be either 80Mhz, 160MHz or 240MHz"); + } + /* + system_update_cpu_freq(freq); + */ + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq); + +STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + enum {ARG_sleep_ms}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_sleep_ms, MP_ARG_INT, { .u_int = 0 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + + mp_int_t expiry = args[ARG_sleep_ms].u_int; + + if (expiry != 0) { + esp_sleep_enable_timer_wakeup(expiry * 1000); + } + + if (machine_rtc_config.ext0_pin != -1 && (machine_rtc_config.ext0_wake_types & wake_type)) { + esp_sleep_enable_ext0_wakeup(machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? 1 : 0); + } + + if (machine_rtc_config.ext1_pins != 0) { + esp_sleep_enable_ext1_wakeup( + machine_rtc_config.ext1_pins, + machine_rtc_config.ext1_level ? ESP_EXT1_WAKEUP_ANY_HIGH : ESP_EXT1_WAKEUP_ALL_LOW); + } + + if (machine_rtc_config.wake_on_touch) { + if (esp_sleep_enable_touchpad_wakeup() != ESP_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "esp_sleep_enable_touchpad_wakeup() failed")); + } + } + + switch(wake_type) { + case MACHINE_WAKE_SLEEP: + esp_light_sleep_start(); + break; + case MACHINE_WAKE_DEEPSLEEP: + esp_deep_sleep_start(); + break; + } + return mp_const_none; +} + +STATIC mp_obj_t machine_sleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "light sleep not available for this version of ESP-IDF")); + return machine_sleep_helper(MACHINE_WAKE_SLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_sleep_obj, 0, machine_sleep); + +STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return machine_sleep_helper(MACHINE_WAKE_DEEPSLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_deepsleep_obj, 0, machine_deepsleep); + +STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + switch(rtc_get_reset_reason(0)) { + case POWERON_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_PWRON_RESET); + break; + case SW_RESET: + case SW_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_SOFT_RESET); + break; + case OWDT_RESET: + case TG0WDT_SYS_RESET: + case TG1WDT_SYS_RESET: + case RTCWDT_SYS_RESET: + case RTCWDT_BROWN_OUT_RESET: + case RTCWDT_CPU_RESET: + case RTCWDT_RTC_RESET: + case TGWDT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_WDT_RESET); + break; + + case DEEPSLEEP_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_DEEPSLEEP_RESET); + break; + + case EXT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_HARD_RESET); + break; + + case NO_MEAN: + case SDIO_RESET: + case INTRUSION_RESET: + default: + return MP_OBJ_NEW_SMALL_INT(0); + break; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_reset_cause_obj, 0, machine_reset_cause); + +STATIC mp_obj_t machine_wake_reason(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return MP_OBJ_NEW_SMALL_INT(esp_sleep_get_wakeup_cause()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_wake_reason_obj, 0, machine_wake_reason); + +STATIC mp_obj_t machine_reset(void) { + esp_restart(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_unique_id(void) { + uint8_t chipid[6]; + esp_efuse_mac_get_default(chipid); + return mp_obj_new_bytes(chipid, 6); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); + +STATIC mp_obj_t machine_idle(void) { + taskYIELD(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); + +STATIC mp_obj_t machine_disable_irq(void) { + uint32_t state = MICROPY_BEGIN_ATOMIC_SECTION(); + return mp_obj_new_int(state); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq); + +STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) { + uint32_t state = mp_obj_get_int(state_in); + MICROPY_END_ATOMIC_SECTION(state); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + + { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, + + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + + { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) }, + + // wake abilities + { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(MACHINE_WAKE_SLEEP) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, + { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, + { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) }, + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, + { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) }, + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, + + // Reset reasons + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(MP_HARD_RESET) }, + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(MP_WDT_RESET) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(MP_DEEPSLEEP_RESET) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(MP_SOFT_RESET) }, + + // Wake reasons + { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) }, + { MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT0_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT1_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT1) }, + { MP_ROM_QSTR(MP_QSTR_TIMER_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TIMER) }, + { MP_ROM_QSTR(MP_QSTR_TOUCHPAD_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TOUCHPAD) }, + { MP_ROM_QSTR(MP_QSTR_ULP_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_ULP) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h new file mode 100644 index 0000000000..c8513a4711 --- /dev/null +++ b/ports/esp32/modmachine.h @@ -0,0 +1,26 @@ +#ifndef MICROPY_INCLUDED_ESP32_MODMACHINE_H +#define MICROPY_INCLUDED_ESP32_MODMACHINE_H + +#include "py/obj.h" + +typedef enum { + //MACHINE_WAKE_IDLE=0x01, + MACHINE_WAKE_SLEEP=0x02, + MACHINE_WAKE_DEEPSLEEP=0x04 +} wake_type_t; + +extern const mp_obj_type_t machine_timer_type; +extern const mp_obj_type_t machine_wdt_type; +extern const mp_obj_type_t machine_pin_type; +extern const mp_obj_type_t machine_touchpad_type; +extern const mp_obj_type_t machine_adc_type; +extern const mp_obj_type_t machine_dac_type; +extern const mp_obj_type_t machine_pwm_type; +extern const mp_obj_type_t machine_hw_spi_type; +extern const mp_obj_type_t machine_uart_type; +extern const mp_obj_type_t machine_rtc_type; + +void machine_pins_init(void); +void machine_pins_deinit(void); + +#endif // MICROPY_INCLUDED_ESP32_MODMACHINE_H diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c new file mode 100644 index 0000000000..fdcb6d3cf3 --- /dev/null +++ b/ports/esp32/modnetwork.c @@ -0,0 +1,646 @@ +/* + * 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 +#include + +#include "py/nlr.h" +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "netutils.h" +#include "esp_wifi.h" +#include "esp_wifi_types.h" +#include "esp_log.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "lwip/dns.h" +#include "tcpip_adapter.h" + +#include "modnetwork.h" + +#define MODNETWORK_INCLUDE_CONSTANTS (1) + +NORETURN void _esp_exceptions(esp_err_t e) { + switch (e) { + case ESP_ERR_WIFI_NOT_INIT: + mp_raise_msg(&mp_type_OSError, "Wifi Not Initialized"); + case ESP_ERR_WIFI_NOT_STARTED: + mp_raise_msg(&mp_type_OSError, "Wifi Not Started"); + case ESP_ERR_WIFI_NOT_STOPPED: + mp_raise_msg(&mp_type_OSError, "Wifi Not Stopped"); + case ESP_ERR_WIFI_IF: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Interface"); + case ESP_ERR_WIFI_MODE: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Mode"); + case ESP_ERR_WIFI_STATE: + mp_raise_msg(&mp_type_OSError, "Wifi Internal State Error"); + case ESP_ERR_WIFI_CONN: + mp_raise_msg(&mp_type_OSError, "Wifi Internal Error"); + case ESP_ERR_WIFI_NVS: + mp_raise_msg(&mp_type_OSError, "Wifi Internal NVS Error"); + case ESP_ERR_WIFI_MAC: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid MAC Address"); + case ESP_ERR_WIFI_SSID: + mp_raise_msg(&mp_type_OSError, "Wifi SSID Invalid"); + case ESP_ERR_WIFI_PASSWORD: + mp_raise_msg(&mp_type_OSError, "Wifi Invalid Password"); + case ESP_ERR_WIFI_TIMEOUT: + mp_raise_OSError(MP_ETIMEDOUT); + case ESP_ERR_WIFI_WAKE_FAIL: + mp_raise_msg(&mp_type_OSError, "Wifi Wakeup Failure"); + case ESP_ERR_WIFI_WOULD_BLOCK: + mp_raise_msg(&mp_type_OSError, "Wifi Would Block"); + case ESP_ERR_WIFI_NOT_CONNECT: + mp_raise_msg(&mp_type_OSError, "Wifi Not Connected"); + case ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS: + mp_raise_msg(&mp_type_OSError, "TCP/IP Invalid Parameters"); + case ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY: + mp_raise_msg(&mp_type_OSError, "TCP/IP IF Not Ready"); + case ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED: + mp_raise_msg(&mp_type_OSError, "TCP/IP DHCP Client Start Failed"); + case ESP_ERR_TCPIP_ADAPTER_NO_MEM: + mp_raise_OSError(MP_ENOMEM); + default: + nlr_raise(mp_obj_new_exception_msg_varg( + &mp_type_RuntimeError, "Wifi Unknown Error 0x%04x", e + )); + } +} + +static inline void esp_exceptions(esp_err_t e) { + if (e != ESP_OK) _esp_exceptions(e); +} + +#define ESP_EXCEPTIONS(x) do { esp_exceptions(x); } while (0); + +typedef struct _wlan_if_obj_t { + mp_obj_base_t base; + int if_id; +} wlan_if_obj_t; + +const mp_obj_type_t wlan_if_type; +STATIC const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA}; +STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP}; + +//static wifi_config_t wifi_ap_config = {{{0}}}; +static wifi_config_t wifi_sta_config = {{{0}}}; + +// Set to "true" if 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; + +// This function is called by the system-event task and so runs in a different +// thread to the main MicroPython task. It must not raise any Python exceptions. +static esp_err_t event_handler(void *ctx, system_event_t *event) { + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + ESP_LOGI("wifi", "STA_START"); + break; + case SYSTEM_EVENT_STA_CONNECTED: + ESP_LOGI("network", "CONNECTED"); + break; + case SYSTEM_EVENT_STA_GOT_IP: + ESP_LOGI("network", "GOT_IP"); + wifi_sta_connected = true; + break; + case SYSTEM_EVENT_STA_DISCONNECTED: { + // This is a workaround as ESP32 WiFi libs don't currently + // auto-reassociate. + system_event_sta_disconnected_t *disconn = &event->event_info.disconnected; + char *message = ""; + 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: + message = "\nauthentication failed"; + wifi_sta_connect_requested = false; + break; + default: + // Let other errors through and try to reconnect. + break; + } + ESP_LOGI("wifi", "STA_DISCONNECTED, reason:%d%s", disconn->reason, message); + + bool reconnected = false; + if (wifi_sta_connect_requested) { + wifi_mode_t mode; + if (esp_wifi_get_mode(&mode) == ESP_OK) { + if (mode & WIFI_MODE_STA) { + // STA is active so attempt to reconnect. + esp_err_t e = esp_wifi_connect(); + if (e != ESP_OK) { + ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e); + } else { + reconnected = true; + } + } + } + } + if (wifi_sta_connected && !reconnected) { + // If already connected and we fail to reconnect + wifi_sta_connected = false; + } + break; + } + default: + ESP_LOGI("network", "event %d", event->event_id); + break; + } + return ESP_OK; +} + +/*void error_check(bool status, const char *msg) { + if (!status) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg)); + } +} +*/ + +STATIC void require_if(mp_obj_t wlan_if, int if_no) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if); + if (self->if_id != if_no) { + mp_raise_msg(&mp_type_OSError, if_no == WIFI_IF_STA ? "STA required" : "AP required"); + } +} + +STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { + 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("invalid WLAN interface identifier"); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan); + +STATIC mp_obj_t esp_initialize() { + static int initialized = 0; + if (!initialized) { + ESP_LOGD("modnetwork", "Initializing TCP/IP"); + tcpip_adapter_init(); + ESP_LOGD("modnetwork", "Initializing Event Loop"); + ESP_EXCEPTIONS( esp_event_loop_init(event_handler, NULL) ); + ESP_LOGD("modnetwork", "esp_event_loop_init done"); + initialized = 1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_initialize_obj, esp_initialize); + +#if (WIFI_MODE_STA & WIFI_MODE_AP != WIFI_MODE_NULL || WIFI_MODE_STA | WIFI_MODE_AP != WIFI_MODE_APSTA) +#error WIFI_MODE_STA and WIFI_MODE_AP are supposed to be bitfields! +#endif + +STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + wifi_mode_t mode; + 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 *args) { + + mp_uint_t len; + const char *p; + if (n_args > 1) { + memset(&wifi_sta_config, 0, sizeof(wifi_sta_config)); + p = mp_obj_str_get_data(args[1], &len); + memcpy(wifi_sta_config.sta.ssid, p, MIN(len, sizeof(wifi_sta_config.sta.ssid))); + p = (n_args > 2) ? mp_obj_str_get_data(args[2], &len) : ""; + memcpy(wifi_sta_config.sta.password, p, MIN(len, sizeof(wifi_sta_config.sta.password))); + ESP_EXCEPTIONS( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config) ); + } + MP_THREAD_GIL_EXIT(); + ESP_EXCEPTIONS( esp_wifi_connect() ); + MP_THREAD_GIL_ENTER(); + wifi_sta_connect_requested = true; + + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 1, 7, esp_connect); + +STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { + wifi_sta_connect_requested = false; + ESP_EXCEPTIONS( esp_wifi_disconnect() ); + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); + +STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // no arguments: return None until link status is implemented + return mp_const_none; + } + + // one argument: return status based on query parameter + switch ((uintptr_t)args[1]) { + case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): { + // return list of connected stations, only if in soft-AP mode + require_if(args[0], WIFI_IF_AP); + wifi_sta_list_t station_list; + ESP_EXCEPTIONS(esp_wifi_ap_get_sta_list(&station_list)); + wifi_sta_info_t *stations = (wifi_sta_info_t*)station_list.sta; + mp_obj_t list = mp_obj_new_list(0, NULL); + for (int i = 0; i < station_list.num; ++i) { + mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL); + t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac)); + mp_obj_list_append(list, t); + } + return list; + } + + default: + mp_raise_ValueError("unknown status param"); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_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) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "STA must be active")); + } + + mp_obj_t list = mp_obj_new_list(0, NULL); + wifi_scan_config_t config = { 0 }; + // XXX how do we scan hidden APs (and if we can scan them, are they really hidden?) + MP_THREAD_GIL_EXIT(); + esp_err_t status = esp_wifi_scan_start(&config, 1); + MP_THREAD_GIL_ENTER(); + if (status == 0) { + uint16_t count = 0; + ESP_EXCEPTIONS( esp_wifi_scan_get_ap_num(&count) ); + wifi_ap_record_t *wifi_ap_records = calloc(count, sizeof(wifi_ap_record_t)); + ESP_EXCEPTIONS( esp_wifi_scan_get_ap_records(&count, wifi_ap_records) ); + for (uint16_t i = 0; i < count; i++) { + mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); + uint8_t *x = memchr(wifi_ap_records[i].ssid, 0, sizeof(wifi_ap_records[i].ssid)); + int ssid_len = x ? x - wifi_ap_records[i].ssid : sizeof(wifi_ap_records[i].ssid); + t->items[0] = mp_obj_new_bytes(wifi_ap_records[i].ssid, ssid_len); + t->items[1] = mp_obj_new_bytes(wifi_ap_records[i].bssid, sizeof(wifi_ap_records[i].bssid)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].primary); + t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].rssi); + t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].authmode); + t->items[5] = mp_const_false; // XXX hidden? + mp_obj_list_append(list, MP_OBJ_FROM_PTR(t)); + } + free(wifi_ap_records); + } + return list; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan); + +STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->if_id == WIFI_IF_STA) { + 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; + tcpip_adapter_dns_info_t dns_info; + tcpip_adapter_get_ip_info(self->if_id, &info); + tcpip_adapter_get_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info); + if (n_args == 1) { + // get + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&info.netmask, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&info.gw, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&dns_info.ip, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else { + // set + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 4, &items); + netutils_parse_ipv4_addr(items[0], (void*)&info.ip, NETUTILS_BIG); + if (mp_obj_is_integer(items[1])) { + // allow numeric netmask, i.e.: + // 24 -> 255.255.255.0 + // 16 -> 255.255.0.0 + // etc... + uint32_t* m = (uint32_t*)&info.netmask; + *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1]))); + } else { + netutils_parse_ipv4_addr(items[1], (void*)&info.netmask, NETUTILS_BIG); + } + netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[3], (void*)&dns_info.ip, NETUTILS_BIG); + // To set a static IP we have to disable DHCP first + if (self->if_id == WIFI_IF_STA || self->if_id == ESP_IF_ETH) { + esp_err_t e = tcpip_adapter_dhcpc_stop(self->if_id); + if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); + ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(self->if_id, &info)); + ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); + } else if (self->if_id == WIFI_IF_AP) { + esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP); + if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e); + ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info)); + ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_AP, TCPIP_ADAPTER_DNS_MAIN, &dns_info)); + ESP_EXCEPTIONS(tcpip_adapter_dhcps_start(WIFI_IF_AP)); + } + return mp_const_none; + } +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig); + +STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + if (n_args != 1 && kwargs->used != 0) { + mp_raise_TypeError("either pos or kw args are allowed"); + } + + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + // get the config for the interface + wifi_config_t cfg; + ESP_EXCEPTIONS(esp_wifi_get_config(self->if_id, &cfg)); + + if (kwargs->used != 0) { + + for (size_t i = 0; i < kwargs->alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { + int req_if = -1; + + #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) + switch ((uintptr_t)kwargs->table[i].key) { + case QS(MP_QSTR_mac): { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != 6) { + mp_raise_ValueError("invalid buffer length"); + } + ESP_EXCEPTIONS(esp_wifi_set_mac(self->if_id, bufinfo.buf)); + break; + } + case QS(MP_QSTR_essid): { + req_if = WIFI_IF_AP; + mp_uint_t len; + const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); + len = MIN(len, sizeof(cfg.ap.ssid)); + memcpy(cfg.ap.ssid, s, len); + cfg.ap.ssid_len = len; + break; + } + case QS(MP_QSTR_hidden): { + req_if = WIFI_IF_AP; + cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_authmode): { + req_if = WIFI_IF_AP; + cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_password): { + req_if = WIFI_IF_AP; + mp_uint_t len; + const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len); + len = MIN(len, sizeof(cfg.ap.password) - 1); + memcpy(cfg.ap.password, s, len); + cfg.ap.password[len] = 0; + break; + } + case QS(MP_QSTR_channel): { + req_if = WIFI_IF_AP; + cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); + break; + } + case QS(MP_QSTR_dhcp_hostname): { + const char *s = mp_obj_str_get_str(kwargs->table[i].value); + ESP_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id, s)); + break; + } + default: + goto unknown; + } + #undef QS + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + } + } + + ESP_EXCEPTIONS(esp_wifi_set_config(self->if_id, &cfg)); + + return mp_const_none; + } + + // Get config + + if (n_args != 2) { + mp_raise_TypeError("can query only one param"); + } + + int req_if = -1; + mp_obj_t val; + + #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) + switch ((uintptr_t)args[1]) { + case QS(MP_QSTR_mac): { + uint8_t mac[6]; + ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac)); + return mp_obj_new_bytes(mac, sizeof(mac)); + } + case QS(MP_QSTR_essid): + if (self->if_id == WIFI_IF_STA) { + val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid)); + } else { + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); + } + break; + case QS(MP_QSTR_hidden): + req_if = WIFI_IF_AP; + 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; + } + default: + goto unknown; + } + #undef QS + + // We post-check interface requirements to save on code size + if (req_if >= 0) { + require_if(args[0], req_if); + } + + return val; + +unknown: + mp_raise_ValueError("unknown config param"); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config); + +STATIC const mp_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); + + +STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_initialize_obj) }, + { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) }, + { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) }, + { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) }, + +#if MODNETWORK_INCLUDE_CONSTANTS + { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(WIFI_IF_STA)}, + { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(WIFI_IF_AP)}, + + { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(WIFI_PROTOCOL_11B) }, + { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(WIFI_PROTOCOL_11G) }, + { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(WIFI_PROTOCOL_11N) }, + + { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(WIFI_AUTH_OPEN) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(WIFI_AUTH_WEP) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(WIFI_AUTH_WPA_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) }, + { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) }, + + { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) }, + { MP_ROM_QSTR(MP_QSTR_PHY_TLK110), MP_ROM_INT(PHY_TLK110) }, +#endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table); + +const mp_obj_module_t mp_module_network = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_network_globals, +}; diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h new file mode 100644 index 0000000000..b8dc1b8528 --- /dev/null +++ b/ports/esp32/modnetwork.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H +#define MICROPY_INCLUDED_ESP32_MODNETWORK_H + +enum { PHY_LAN8720, PHY_TLK110 }; + +MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj); + +void usocket_events_deinit(void); + +#endif diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c new file mode 100644 index 0000000000..daa77f581c --- /dev/null +++ b/ports/esp32/modsocket.c @@ -0,0 +1,702 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * and Mnemote Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016, 2017 Nick Moore @mnemote + * + * Based on extmod/modlwip.c + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Galen Hazelwood + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "py/runtime0.h" +#include "py/nlr.h" +#include "py/objlist.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "lib/netutils/netutils.h" +#include "tcpip_adapter.h" +#include "modnetwork.h" + +#include "lwip/sockets.h" +#include "lwip/netdb.h" +#include "lwip/ip4.h" +#include "lwip/igmp.h" +#include "esp_log.h" + +#define SOCKET_POLL_US (100000) + +typedef struct _socket_obj_t { + mp_obj_base_t base; + int fd; + uint8_t domain; + uint8_t type; + uint8_t proto; + bool peer_closed; + unsigned int retries; + #if MICROPY_PY_USOCKET_EVENTS + mp_obj_t events_callback; + struct _socket_obj_t *events_next; + #endif +} socket_obj_t; + +void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms); + +#if MICROPY_PY_USOCKET_EVENTS +// Support for callbacks on asynchronous socket events (when socket becomes readable) + +// This divisor is used to reduce the load on the system, so it doesn't poll sockets too often +#define USOCKET_EVENTS_DIVISOR (8) + +STATIC uint8_t usocket_events_divisor; +STATIC socket_obj_t *usocket_events_head; + +void usocket_events_deinit(void) { + usocket_events_head = NULL; +} + +// Assumes the socket is not already in the linked list, and adds it +STATIC void usocket_events_add(socket_obj_t *sock) { + sock->events_next = usocket_events_head; + usocket_events_head = sock; +} + +// Assumes the socket is already in the linked list, and removes it +STATIC void usocket_events_remove(socket_obj_t *sock) { + for (socket_obj_t **s = &usocket_events_head;; s = &(*s)->events_next) { + if (*s == sock) { + *s = (*s)->events_next; + return; + } + } +} + +// Polls all registered sockets for readability and calls their callback if they are readable +void usocket_events_handler(void) { + if (usocket_events_head == NULL) { + return; + } + if (--usocket_events_divisor) { + return; + } + usocket_events_divisor = USOCKET_EVENTS_DIVISOR; + + fd_set rfds; + FD_ZERO(&rfds); + int max_fd = 0; + + for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) { + FD_SET(s->fd, &rfds); + max_fd = MAX(max_fd, s->fd); + } + + // Poll the sockets + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + int r = select(max_fd + 1, &rfds, NULL, NULL, &timeout); + if (r <= 0) { + return; + } + + // Call the callbacks + for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) { + if (FD_ISSET(s->fd, &rfds)) { + mp_call_function_1_protected(s->events_callback, s); + } + } +} + +#endif // MICROPY_PY_USOCKET_EVENTS + +NORETURN static void exception_from_errno(int _errno) { + // Here we need to convert from lwip errno values to MicroPython's standard ones + if (_errno == EINPROGRESS) { + _errno = MP_EINPROGRESS; + } + mp_raise_OSError(_errno); +} + +static inline void check_for_exceptions(void) { + mp_handle_pending(); +} + +static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) { + const struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + }; + + mp_obj_t port = portx; + if (MP_OBJ_IS_SMALL_INT(port)) { + // This is perverse, because lwip_getaddrinfo promptly converts it back to an int, but + // that's the API we have to work with ... + port = mp_obj_str_binary_op(MP_BINARY_OP_MODULO, mp_obj_new_str_via_qstr("%s", 2), port); + } + + const char *host_str = mp_obj_str_get_str(host); + const char *port_str = mp_obj_str_get_str(port); + + if (host_str[0] == '\0') { + // a host of "" is equivalent to the default/all-local IP address + host_str = "0.0.0.0"; + } + + MP_THREAD_GIL_EXIT(); + int res = lwip_getaddrinfo(host_str, port_str, &hints, resp); + MP_THREAD_GIL_ENTER(); + + return res; +} + +int _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) { + mp_uint_t len = 0; + mp_obj_t *elem; + mp_obj_get_array(addrtuple, &len, &elem); + if (len != 2) return -1; + return _socket_getaddrinfo2(elem[0], elem[1], resp); +} + +STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + struct addrinfo *res; + _socket_getaddrinfo(arg1, &res); + int r = lwip_bind_r(self->fd, res->ai_addr, res->ai_addrlen); + lwip_freeaddrinfo(res); + if (r < 0) exception_from_errno(errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + int backlog = mp_obj_get_int(arg1); + int r = lwip_listen_r(self->fd, backlog); + if (r < 0) exception_from_errno(errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); + +STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + + struct sockaddr addr; + socklen_t addr_len = sizeof(addr); + + int new_fd = -1; + for (int i=0; i<=self->retries; i++) { + MP_THREAD_GIL_EXIT(); + new_fd = lwip_accept_r(self->fd, &addr, &addr_len); + MP_THREAD_GIL_ENTER(); + if (new_fd >= 0) break; + if (errno != EAGAIN) exception_from_errno(errno); + check_for_exceptions(); + } + if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT); + + // create new socket object + socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); + sock->base.type = self->base.type; + sock->fd = new_fd; + sock->domain = self->domain; + sock->type = self->type; + sock->proto = self->proto; + sock->peer_closed = false; + _socket_settimeout(sock, UINT64_MAX); + + // make the return value + uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&addr)->sin_addr; + mp_uint_t port = lwip_ntohs(((struct sockaddr_in*)&addr)->sin_port); + mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); + client->items[0] = sock; + client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + + return client; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + struct addrinfo *res; + _socket_getaddrinfo(arg1, &res); + MP_THREAD_GIL_EXIT(); + int r = lwip_connect_r(self->fd, res->ai_addr, res->ai_addrlen); + MP_THREAD_GIL_ENTER(); + lwip_freeaddrinfo(res); + if (r != 0) { + exception_from_errno(errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { + (void)n_args; // always 4 + socket_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + int opt = mp_obj_get_int(args[2]); + + switch (opt) { + // level: SOL_SOCKET + case SO_REUSEADDR: { + int val = mp_obj_get_int(args[3]); + int ret = lwip_setsockopt_r(self->fd, SOL_SOCKET, opt, &val, sizeof(int)); + if (ret != 0) { + exception_from_errno(errno); + } + break; + } + + #if MICROPY_PY_USOCKET_EVENTS + // level: SOL_SOCKET + // special "register callback" option + case 20: { + if (args[3] == mp_const_none) { + if (self->events_callback != MP_OBJ_NULL) { + usocket_events_remove(self); + self->events_callback = MP_OBJ_NULL; + } + } else { + if (self->events_callback == MP_OBJ_NULL) { + usocket_events_add(self); + } + self->events_callback = args[3]; + } + break; + } + #endif + + // level: IPPROTO_IP + case IP_ADD_MEMBERSHIP: { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != sizeof(ip4_addr_t) * 2) { + mp_raise_ValueError(NULL); + } + + // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa + err_t err = igmp_joingroup((const ip4_addr_t*)bufinfo.buf + 1, bufinfo.buf); + if (err != ERR_OK) { + mp_raise_OSError(-err); + } + break; + } + + default: + mp_printf(&mp_plat_print, "Warning: lwip.setsockopt() option not implemented\n"); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms) { + // Rather than waiting for the entire timeout specified, we wait sock->retries times + // for SOCKET_POLL_US each, checking for a MicroPython interrupt between timeouts. + // with SOCKET_POLL_MS == 100ms, sock->retries allows for timeouts up to 13 years. + // if timeout_ms == UINT64_MAX, wait forever. + sock->retries = (timeout_ms == UINT64_MAX) ? UINT_MAX : timeout_ms * 1000 / SOCKET_POLL_US; + + struct timeval timeout = { + .tv_sec = 0, + .tv_usec = timeout_ms ? SOCKET_POLL_US : 0 + }; + lwip_setsockopt_r(sock->fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout)); + lwip_setsockopt_r(sock->fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout)); + lwip_fcntl_r(sock->fd, F_SETFL, timeout_ms ? 0 : O_NONBLOCK); +} + +STATIC mp_obj_t socket_settimeout(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + if (arg1 == mp_const_none) _socket_settimeout(self, UINT64_MAX); + else _socket_settimeout(self, mp_obj_get_float(arg1) * 1000L); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout); + +STATIC mp_obj_t socket_setblocking(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + if (mp_obj_is_true(arg1)) _socket_settimeout(self, UINT64_MAX); + else _socket_settimeout(self, 0); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +// XXX this can end up waiting a very long time if the content is dribbled in one character +// at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not +// good behaviour. +STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size, + struct sockaddr *from, socklen_t *from_len, int *errcode) { + socket_obj_t *sock = MP_OBJ_TO_PTR(self_in); + + // If the peer closed the connection then the lwIP socket API will only return "0" once + // from lwip_recvfrom_r and then block on subsequent calls. To emulate POSIX behaviour, + // which continues to return "0" for each call on a closed socket, we set a flag when + // the peer closed the socket. + if (sock->peer_closed) { + return 0; + } + + // XXX Would be nicer to use RTC to handle timeouts + for (int i = 0; i <= sock->retries; ++i) { + MP_THREAD_GIL_EXIT(); + int r = lwip_recvfrom_r(sock->fd, buf, size, 0, from, from_len); + MP_THREAD_GIL_ENTER(); + if (r == 0) { + sock->peer_closed = true; + } + if (r >= 0) { + return r; + } + if (errno != EWOULDBLOCK) { + *errcode = errno; + return MP_STREAM_ERROR; + } + check_for_exceptions(); + } + + *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT; + return MP_STREAM_ERROR; +} + +mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in, + struct sockaddr *from, socklen_t *from_len) { + size_t len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + + int errcode; + mp_uint_t ret = _socket_read_data(self_in, vstr.buf, len, from, from_len, &errcode); + if (ret == MP_STREAM_ERROR) { + exception_from_errno(errcode); + } + + vstr.len = ret; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} + +STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + return _socket_recvfrom(self_in, len_in, NULL, NULL); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); + +STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { + struct sockaddr from; + socklen_t fromlen = sizeof(from); + + mp_obj_t tuple[2]; + tuple[0] = _socket_recvfrom(self_in, len_in, &from, &fromlen); + + uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&from)->sin_addr; + mp_uint_t port = lwip_ntohs(((struct sockaddr_in*)&from)->sin_port); + tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom); + +int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) { + int sentlen = 0; + for (int i=0; i<=sock->retries && sentlen < datalen; i++) { + MP_THREAD_GIL_EXIT(); + int r = lwip_write_r(sock->fd, data+sentlen, datalen-sentlen); + MP_THREAD_GIL_ENTER(); + if (r < 0 && errno != EWOULDBLOCK) exception_from_errno(errno); + if (r > 0) sentlen += r; + check_for_exceptions(); + } + if (sentlen == 0) mp_raise_OSError(MP_ETIMEDOUT); + return sentlen; +} + +STATIC mp_obj_t socket_send(const mp_obj_t arg0, const mp_obj_t arg1) { + socket_obj_t *sock = MP_OBJ_TO_PTR(arg0); + mp_uint_t datalen; + const char *data = mp_obj_str_get_data(arg1, &datalen); + int r = _socket_send(sock, data, datalen); + return mp_obj_new_int(r); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + +STATIC mp_obj_t socket_sendall(const mp_obj_t arg0, const mp_obj_t arg1) { + // XXX behaviour when nonblocking (see extmod/modlwip.c) + // XXX also timeout behaviour. + socket_obj_t *sock = MP_OBJ_TO_PTR(arg0); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg1, &bufinfo, MP_BUFFER_READ); + int r = _socket_send(sock, bufinfo.buf, bufinfo.len); + if (r < bufinfo.len) mp_raise_OSError(MP_ETIMEDOUT); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_sendall_obj, socket_sendall); + +STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get the buffer to send + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); + + // create the destination address + struct sockaddr_in to; + to.sin_len = sizeof(to); + to.sin_family = AF_INET; + to.sin_port = lwip_htons(netutils_parse_inet_addr(addr_in, (uint8_t*)&to.sin_addr, NETUTILS_BIG)); + + // send the data + for (int i=0; i<=self->retries; i++) { + MP_THREAD_GIL_EXIT(); + int ret = lwip_sendto_r(self->fd, bufinfo.buf, bufinfo.len, 0, (struct sockaddr*)&to, sizeof(to)); + MP_THREAD_GIL_ENTER(); + if (ret > 0) return mp_obj_new_int_from_uint(ret); + if (ret == -1 && errno != EWOULDBLOCK) { + exception_from_errno(errno); + } + check_for_exceptions(); + } + mp_raise_OSError(MP_ETIMEDOUT); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto); + +STATIC mp_obj_t socket_fileno(const mp_obj_t arg0) { + socket_obj_t *self = MP_OBJ_TO_PTR(arg0); + return mp_obj_new_int(self->fd); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno); + +STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); + +STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + return _socket_read_data(self_in, buf, size, NULL, NULL, errcode); +} + +STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + socket_obj_t *sock = self_in; + for (int i=0; i<=sock->retries; i++) { + MP_THREAD_GIL_EXIT(); + int r = lwip_write_r(sock->fd, buf, size); + MP_THREAD_GIL_ENTER(); + if (r > 0) return r; + if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; } + check_for_exceptions(); + } + *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT; + return MP_STREAM_ERROR; +} + +STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + socket_obj_t * socket = self_in; + if (request == MP_STREAM_POLL) { + + fd_set rfds; FD_ZERO(&rfds); + fd_set wfds; FD_ZERO(&wfds); + fd_set efds; FD_ZERO(&efds); + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 }; + if (arg & MP_STREAM_POLL_RD) FD_SET(socket->fd, &rfds); + if (arg & MP_STREAM_POLL_WR) FD_SET(socket->fd, &wfds); + if (arg & MP_STREAM_POLL_HUP) FD_SET(socket->fd, &efds); + + int r = select((socket->fd)+1, &rfds, &wfds, &efds, &timeout); + if (r < 0) { + *errcode = MP_EIO; + return MP_STREAM_ERROR; + } + + mp_uint_t ret = 0; + if (FD_ISSET(socket->fd, &rfds)) ret |= MP_STREAM_POLL_RD; + if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR; + if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP; + return ret; + } else if (request == MP_STREAM_CLOSE) { + if (socket->fd >= 0) { + #if MICROPY_PY_USOCKET_EVENTS + if (socket->events_callback != MP_OBJ_NULL) { + usocket_events_remove(socket); + socket->events_callback = MP_OBJ_NULL; + } + #endif + int ret = lwip_close_r(socket->fd); + if (ret != 0) { + *errcode = errno; + return MP_STREAM_ERROR; + } + socket->fd = -1; + } + return 0; + } + + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; +} + +STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_sendall_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, + { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) }, + { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&socket_fileno_obj) }, + + { MP_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); + +STATIC const mp_stream_p_t socket_stream_p = { + .read = socket_stream_read, + .write = socket_stream_write, + .ioctl = socket_stream_ioctl +}; + +STATIC const mp_obj_type_t socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .protocol = &socket_stream_p, + .locals_dict = (mp_obj_t)&socket_locals_dict, +}; + +STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) { + socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); + sock->base.type = &socket_type; + sock->domain = AF_INET; + sock->type = SOCK_STREAM; + sock->proto = 0; + sock->peer_closed = false; + if (n_args > 0) { + sock->domain = mp_obj_get_int(args[0]); + if (n_args > 1) { + sock->type = mp_obj_get_int(args[1]); + if (n_args > 2) { + sock->proto = mp_obj_get_int(args[2]); + } + } + } + + sock->fd = lwip_socket(sock->domain, sock->type, sock->proto); + if (sock->fd < 0) { + exception_from_errno(errno); + } + _socket_settimeout(sock, UINT64_MAX); + + return MP_OBJ_FROM_PTR(sock); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket); + +STATIC mp_obj_t esp_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { + // TODO support additional args beyond the first two + + struct addrinfo *res = NULL; + _socket_getaddrinfo2(args[0], args[1], &res); + mp_obj_t ret_list = mp_obj_new_list(0, NULL); + + for (struct addrinfo *resi = res; resi; resi = resi->ai_next) { + mp_obj_t addrinfo_objs[5] = { + mp_obj_new_int(resi->ai_family), + mp_obj_new_int(resi->ai_socktype), + mp_obj_new_int(resi->ai_protocol), + mp_obj_new_str(resi->ai_canonname, strlen(resi->ai_canonname)), + mp_const_none + }; + + if (resi->ai_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)resi->ai_addr; + // This looks odd, but it's really just a u32_t + ip4_addr_t ip4_addr = { .addr = addr->sin_addr.s_addr }; + char buf[16]; + ip4addr_ntoa_r(&ip4_addr, buf, sizeof(buf)); + mp_obj_t inaddr_objs[2] = { + mp_obj_new_str(buf, strlen(buf)), + mp_obj_new_int(ntohs(addr->sin_port)) + }; + addrinfo_objs[4] = mp_obj_new_tuple(2, inaddr_objs); + } + mp_obj_list_append(ret_list, mp_obj_new_tuple(5, addrinfo_objs)); + } + + if (res) lwip_freeaddrinfo(res); + return ret_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_socket_getaddrinfo_obj, 2, 6, esp_socket_getaddrinfo); + +STATIC mp_obj_t esp_socket_initialize() { + static int initialized = 0; + if (!initialized) { + ESP_LOGI("modsocket", "Initializing"); + tcpip_adapter_init(); + initialized = 1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_socket_initialize_obj, esp_socket_initialize); + +STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_socket_initialize_obj) }, + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&get_socket_obj) }, + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&esp_socket_getaddrinfo_obj) }, + + { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) }, + { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(AF_INET6) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCK_STREAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCK_DGRAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(SOCK_RAW) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IPPROTO_TCP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(IPPROTO_UDP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(IPPROTO_IP) }, + { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(SOL_SOCKET) }, + { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SO_REUSEADDR) }, + { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table); + +const mp_obj_module_t mp_module_usocket = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_socket_globals, +}; diff --git a/ports/esp32/modules/_boot.py b/ports/esp32/modules/_boot.py new file mode 100644 index 0000000000..bf40ea3a9f --- /dev/null +++ b/ports/esp32/modules/_boot.py @@ -0,0 +1,12 @@ +import gc +import uos +from flashbdev import bdev + +try: + if bdev: + uos.mount(bdev, '/') +except OSError: + import inisetup + vfs = inisetup.setup() + +gc.collect() diff --git a/ports/esp32/modules/apa106.py b/ports/esp32/modules/apa106.py new file mode 100644 index 0000000000..ef971d78ba --- /dev/null +++ b/ports/esp32/modules/apa106.py @@ -0,0 +1,8 @@ +# APA106driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from neopixel import NeoPixel + + +class APA106(NeoPixel): + ORDER = (0, 1, 2, 3) diff --git a/ports/esp32/modules/dht.py b/ports/esp32/modules/dht.py new file mode 120000 index 0000000000..2aa2f5cbfe --- /dev/null +++ b/ports/esp32/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file diff --git a/ports/esp32/modules/ds18x20.py b/ports/esp32/modules/ds18x20.py new file mode 120000 index 0000000000..9721929a3f --- /dev/null +++ b/ports/esp32/modules/ds18x20.py @@ -0,0 +1 @@ +../../esp8266/modules/ds18x20.py \ No newline at end of file diff --git a/ports/esp32/modules/flashbdev.py b/ports/esp32/modules/flashbdev.py new file mode 100644 index 0000000000..935f5342fc --- /dev/null +++ b/ports/esp32/modules/flashbdev.py @@ -0,0 +1,34 @@ +import esp + +class FlashBdev: + + SEC_SIZE = 4096 + START_SEC = esp.flash_user_start() // SEC_SIZE + + def __init__(self, blocks): + self.blocks = blocks + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + esp.flash_read((n + self.START_SEC) * self.SEC_SIZE, buf) + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + #assert len(buf) <= self.SEC_SIZE, len(buf) + esp.flash_erase(n + self.START_SEC) + esp.flash_write((n + self.START_SEC) * self.SEC_SIZE, buf) + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return self.blocks + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + +size = esp.flash_size() +if size < 1024*1024: + # flash too small for a filesystem + bdev = None +else: + # for now we use a fixed size for the filesystem + bdev = FlashBdev(2048 * 1024 // FlashBdev.SEC_SIZE) diff --git a/ports/esp32/modules/inisetup.py b/ports/esp32/modules/inisetup.py new file mode 100644 index 0000000000..0e9c72fe86 --- /dev/null +++ b/ports/esp32/modules/inisetup.py @@ -0,0 +1,42 @@ +import uos +from flashbdev import bdev + +def check_bootsec(): + buf = bytearray(bdev.SEC_SIZE) + bdev.readblocks(0, buf) + empty = True + for b in buf: + if b != 0xff: + empty = False + break + if empty: + return True + fs_corrupted() + +def fs_corrupted(): + import time + while 1: + print("""\ +FAT filesystem appears to be corrupted. If you had important data there, you +may want to make a flash snapshot to try to recover it. Otherwise, perform +factory reprogramming of MicroPython firmware (completely erase flash, followed +by firmware programming). +""") + time.sleep(3) + +def setup(): + check_bootsec() + print("Performing initial setup") + uos.VfsFat.mkfs(bdev) + vfs = uos.VfsFat(bdev) + uos.mount(vfs, '/flash') + uos.chdir('/flash') + with open("boot.py", "w") as f: + f.write("""\ +# This file is executed on every boot (including wake-boot from deepsleep) +#import esp +#esp.osdebug(None) +#import webrepl +#webrepl.start() +""") + return vfs diff --git a/ports/esp32/modules/neopixel.py b/ports/esp32/modules/neopixel.py new file mode 100644 index 0000000000..86c1586cdd --- /dev/null +++ b/ports/esp32/modules/neopixel.py @@ -0,0 +1,33 @@ +# NeoPixel driver for MicroPython on ESP32 +# MIT license; Copyright (c) 2016 Damien P. George + +from esp import neopixel_write + + +class NeoPixel: + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3, timing=0): + self.pin = pin + self.n = n + self.bpp = bpp + self.buf = bytearray(n * bpp) + self.pin.init(pin.OUT) + self.timing = timing + + def __setitem__(self, index, val): + offset = index * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = val[i] + + def __getitem__(self, index): + offset = index * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] + for i in range(self.bpp)) + + def fill(self, color): + for i in range(self.n): + self[i] = color + + def write(self): + neopixel_write(self.pin, self.buf, self.timing) diff --git a/ports/esp32/modules/ntptime.py b/ports/esp32/modules/ntptime.py new file mode 120000 index 0000000000..e90900d5a9 --- /dev/null +++ b/ports/esp32/modules/ntptime.py @@ -0,0 +1 @@ +../../esp8266/modules/ntptime.py \ No newline at end of file diff --git a/ports/esp32/modules/onewire.py b/ports/esp32/modules/onewire.py new file mode 120000 index 0000000000..091629488e --- /dev/null +++ b/ports/esp32/modules/onewire.py @@ -0,0 +1 @@ +../../esp8266/modules/onewire.py \ No newline at end of file diff --git a/ports/esp32/modules/umqtt/robust.py b/ports/esp32/modules/umqtt/robust.py new file mode 120000 index 0000000000..6bfbbcf552 --- /dev/null +++ b/ports/esp32/modules/umqtt/robust.py @@ -0,0 +1 @@ +../../../../../micropython-lib/umqtt.robust/umqtt/robust.py \ No newline at end of file diff --git a/ports/esp32/modules/umqtt/simple.py b/ports/esp32/modules/umqtt/simple.py new file mode 120000 index 0000000000..6419a46647 --- /dev/null +++ b/ports/esp32/modules/umqtt/simple.py @@ -0,0 +1 @@ +../../../../../micropython-lib/umqtt.simple/umqtt/simple.py \ No newline at end of file diff --git a/ports/esp32/modules/upip.py b/ports/esp32/modules/upip.py new file mode 120000 index 0000000000..130eb69016 --- /dev/null +++ b/ports/esp32/modules/upip.py @@ -0,0 +1 @@ +../../../tools/upip.py \ No newline at end of file diff --git a/ports/esp32/modules/upip_utarfile.py b/ports/esp32/modules/upip_utarfile.py new file mode 120000 index 0000000000..d9653d6a60 --- /dev/null +++ b/ports/esp32/modules/upip_utarfile.py @@ -0,0 +1 @@ +../../../tools/upip_utarfile.py \ No newline at end of file diff --git a/ports/esp32/modules/upysh.py b/ports/esp32/modules/upysh.py new file mode 120000 index 0000000000..12d100c29c --- /dev/null +++ b/ports/esp32/modules/upysh.py @@ -0,0 +1 @@ +../../../../micropython-lib/upysh/upysh.py \ No newline at end of file diff --git a/ports/esp32/modules/urequests.py b/ports/esp32/modules/urequests.py new file mode 120000 index 0000000000..76661112e1 --- /dev/null +++ b/ports/esp32/modules/urequests.py @@ -0,0 +1 @@ +../../../../micropython-lib/urequests/urequests.py \ No newline at end of file diff --git a/ports/esp32/modules/webrepl.py b/ports/esp32/modules/webrepl.py new file mode 120000 index 0000000000..2a3987a729 --- /dev/null +++ b/ports/esp32/modules/webrepl.py @@ -0,0 +1 @@ +../../esp8266/modules/webrepl.py \ No newline at end of file diff --git a/ports/esp32/modules/webrepl_setup.py b/ports/esp32/modules/webrepl_setup.py new file mode 120000 index 0000000000..999888bf13 --- /dev/null +++ b/ports/esp32/modules/webrepl_setup.py @@ -0,0 +1 @@ +../../esp8266/modules/webrepl_setup.py \ No newline at end of file diff --git a/ports/esp32/modules/websocket_helper.py b/ports/esp32/modules/websocket_helper.py new file mode 120000 index 0000000000..4bcf3bcb6a --- /dev/null +++ b/ports/esp32/modules/websocket_helper.py @@ -0,0 +1 @@ +../../esp8266/modules/websocket_helper.py \ No newline at end of file diff --git a/ports/esp32/moduos.c b/ports/esp32/moduos.c new file mode 100644 index 0000000000..dc85136f3d --- /dev/null +++ b/ports/esp32/moduos.c @@ -0,0 +1,134 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "esp_system.h" + +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/misc.h" +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "genhdr/mpversion.h" + +extern const mp_obj_type_t mp_fat_vfs_type; + +STATIC const qstr os_uname_info_fields[] = { + MP_QSTR_sysname, MP_QSTR_nodename, + MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine +}; +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, MICROPY_VERSION_STRING); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE); +STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME); + +STATIC MP_DEFINE_ATTRTUPLE( + os_uname_info_obj, + os_uname_info_fields, + 5, + (mp_obj_t)&os_uname_info_sysname_obj, + (mp_obj_t)&os_uname_info_nodename_obj, + (mp_obj_t)&os_uname_info_release_obj, + (mp_obj_t)&os_uname_info_version_obj, + (mp_obj_t)&os_uname_info_machine_obj +); + +STATIC mp_obj_t os_uname(void) { + return (mp_obj_t)&os_uname_info_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); + +STATIC mp_obj_t os_urandom(mp_obj_t num) { + mp_int_t n = mp_obj_get_int(num); + vstr_t vstr; + vstr_init_len(&vstr, n); + uint32_t r = 0; + for (int i = 0; i < n; i++) { + if ((i & 3) == 0) { + r = esp_random(); // returns 32-bit hardware random number + } + vstr.buf[i] = r; + r >>= 8; + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); + +#if MICROPY_PY_OS_DUPTERM +STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { + (void)obj_in; + 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) }, + { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, + { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) }, + #endif + #if MICROPY_VFS + { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + #if MICROPY_VFS_FAT + { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #endif + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); + +const mp_obj_module_t uos_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&os_module_globals, +}; diff --git a/ports/esp32/modutime.c b/ports/esp32/modutime.c new file mode 100644 index 0000000000..002854298b --- /dev/null +++ b/ports/esp32/modutime.c @@ -0,0 +1,106 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "lib/timeutils/timeutils.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { + timeutils_struct_time_t tm; + mp_int_t seconds; + if (n_args == 0 || args[0] == mp_const_none) { + struct timeval tv; + gettimeofday(&tv, NULL); + seconds = tv.tv_sec; + } else { + seconds = mp_obj_get_int(args[0]); + } + timeutils_seconds_since_2000_to_struct_time(seconds, &tm); + mp_obj_t tuple[8] = { + tuple[0] = mp_obj_new_int(tm.tm_year), + tuple[1] = mp_obj_new_int(tm.tm_mon), + tuple[2] = mp_obj_new_int(tm.tm_mday), + tuple[3] = mp_obj_new_int(tm.tm_hour), + tuple[4] = mp_obj_new_int(tm.tm_min), + tuple[5] = mp_obj_new_int(tm.tm_sec), + tuple[6] = mp_obj_new_int(tm.tm_wday), + tuple[7] = mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); + +STATIC mp_obj_t time_mktime(mp_obj_t tuple) { + size_t len; + mp_obj_t *elem; + mp_obj_get_array(tuple, &len, &elem); + + // localtime generates a tuple of len 8. CPython uses 9, so we accept both. + if (len < 8 || len > 9) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len)); + } + + return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), + mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]), + mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); + +STATIC mp_obj_t time_time(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return mp_obj_new_int(tv.tv_sec); +} +MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t utime_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +}; diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h new file mode 100644 index 0000000000..963aca2efa --- /dev/null +++ b/ports/esp32/mpconfigport.h @@ -0,0 +1,268 @@ +// Options to control how MicroPython is built for this port, +// overriding defaults in py/mpconfig.h. + +#include +#include +#include "rom/ets_sys.h" + +// object representation and NLR handling +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A) +#define MICROPY_NLR_SETJMP (1) + +// memory allocation policies +#define MICROPY_ALLOC_PATH_MAX (128) + +// emitters +#define MICROPY_PERSISTENT_CODE_LOAD (1) + +// compiler configuration +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) + +// optimisations +#define MICROPY_OPT_COMPUTED_GOTO (1) +#define MICROPY_OPT_MPZ_BITWISE (1) + +// Python internal features +#define MICROPY_READER_VFS (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) +#define MICROPY_KBD_EXCEPTION (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_EMACS_KEYS (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) +#define MICROPY_WARNINGS (1) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (1) +#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_STREAMS_POSIX_API (1) +#define MICROPY_MODULE_BUILTIN_INIT (1) +#define MICROPY_MODULE_WEAK_LINKS (1) +#define MICROPY_MODULE_FROZEN_STR (0) +#define MICROPY_MODULE_FROZEN_MPY (1) +#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool +#define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf +#define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_SCHEDULER_DEPTH (8) +#define MICROPY_VFS (1) +#define MICROPY_VFS_FAT (1) + +// control over Python builtins +#define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_STR_BYTES_CMP_WARN (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) +#define MICROPY_PY_BUILTINS_STR_PARTITION (1) +#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_SET (1) +#define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) +#define MICROPY_PY_BUILTINS_TIMEOUTERROR (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) +#define MICROPY_PY_BUILTINS_ENUMERATE (1) +#define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_BUILTINS_FILTER (1) +#define MICROPY_PY_BUILTINS_REVERSED (1) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) +#define MICROPY_PY_BUILTINS_INPUT (1) +#define MICROPY_PY_BUILTINS_MIN_MAX (1) +#define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_TEXT esp32_help_text +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#define MICROPY_PY___FILE__ (1) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_ATTRTUPLE (1) +#define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) +#define MICROPY_PY_MATH (1) +#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) +#define MICROPY_PY_CMATH (1) +#define MICROPY_PY_GC (1) +#define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_IO_BYTESIO (1) +#define MICROPY_PY_IO_BUFFEREDWRITER (1) +#define MICROPY_PY_STRUCT (1) +#define MICROPY_PY_SYS (1) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_SYS_MODULES (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_SYS_STDIO_BUFFER (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_USELECT (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_THREAD (1) +#define MICROPY_PY_THREAD_GIL (1) +#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32) + +// extended modules +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UTIMEQ (1) +#define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_UHASHLIB_SHA1 (1) +#define MICROPY_PY_UHASHLIB_SHA256 (1) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_OS_DUPTERM (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new +#define MICROPY_PY_MACHINE_PULSE (1) +#define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SPI (1) +#define MICROPY_PY_MACHINE_SPI_MSB (0) +#define MICROPY_PY_MACHINE_SPI_LSB (1) +#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly +#define MICROPY_PY_USSL (1) +#define MICROPY_SSL_MBEDTLS (1) +#define MICROPY_PY_USSL_FINALISER (1) +#define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_PY_WEBREPL (1) +#define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL) + +// fatfs configuration +#define MICROPY_FATFS_ENABLE_LFN (1) +#define MICROPY_FATFS_RPATH (2) +#define MICROPY_FATFS_MAX_SS (4096) +#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, + +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t esp_module; +extern const struct _mp_obj_module_t esp32_module; +extern const struct _mp_obj_module_t utime_module; +extern const struct _mp_obj_module_t uos_module; +extern const struct _mp_obj_module_t mp_module_usocket; +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_network; +extern const struct _mp_obj_module_t mp_module_onewire; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_esp32), (mp_obj_t)&esp32_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_collections), (mp_obj_t)&mp_module_collections }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_hashlib), (mp_obj_t)&mp_module_uhashlib }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_heapq), (mp_obj_t)&mp_module_uheapq }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_io), (mp_obj_t)&mp_module_io }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&mp_module_urandom }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_zlib), (mp_obj_t)&mp_module_uzlib }, \ + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; \ + mp_obj_t machine_pin_irq_handler[40]; \ + +// type definitions for the specific machine + +#define BYTES_PER_WORD (4) +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p))) +#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +#define MP_SSIZE_MAX (0x7fffffff) + +// Note: these "critical nested" macros do not ensure cross-CPU exclusion, +// the only disable interrupts on the current CPU. To full manage exclusion +// one should use portENTER_CRITICAL/portEXIT_CRITICAL instead. +#include "freertos/FreeRTOS.h" +#define MICROPY_BEGIN_ATOMIC_SECTION() portENTER_CRITICAL_NESTED() +#define MICROPY_END_ATOMIC_SECTION(state) portEXIT_CRITICAL_NESTED(state) + +#if MICROPY_PY_USOCKET_EVENTS +#define MICROPY_PY_USOCKET_EVENTS_HANDLER extern void usocket_events_handler(void); usocket_events_handler(); +#else +#define MICROPY_PY_USOCKET_EVENTS_HANDLER +#endif + +#if MICROPY_PY_THREAD +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + MICROPY_PY_USOCKET_EVENTS_HANDLER \ + MP_THREAD_GIL_EXIT(); \ + MP_THREAD_GIL_ENTER(); \ + } while (0); +#else +#define MICROPY_EVENT_POLL_HOOK \ + do { \ + extern void mp_handle_pending(void); \ + mp_handle_pending(); \ + MICROPY_PY_USOCKET_EVENTS_HANDLER \ + asm("waiti 0"); \ + } while (0); +#endif + +#define UINT_FMT "%u" +#define INT_FMT "%d" + +typedef int32_t mp_int_t; // must be pointer size +typedef uint32_t mp_uint_t; // must be pointer size +typedef long mp_off_t; +// ssize_t, off_t as required by POSIX-signatured functions in stream.h +#include + +// board specifics + +#define MICROPY_HW_BOARD_NAME "ESP32 module" +#define MICROPY_HW_MCU_NAME "ESP32" +#define MICROPY_PY_SYS_PLATFORM "esp32" diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c new file mode 100644 index 0000000000..353e1343b0 --- /dev/null +++ b/ports/esp32/mphalport.c @@ -0,0 +1,156 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "rom/uart.h" + +#include "py/obj.h" +#include "py/mpstate.h" +#include "py/mphal.h" +#include "extmod/misc.h" +#include "lib/utils/pyexec.h" + +STATIC uint8_t stdin_ringbuf_array[256]; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array)}; + +int mp_hal_stdin_rx_chr(void) { + for (;;) { + int c = ringbuf_get(&stdin_ringbuf); + if (c != -1) { + return c; + } + MICROPY_EVENT_POLL_HOOK + vTaskDelay(1); + } +} + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} + +void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { + MP_THREAD_GIL_EXIT(); + for (uint32_t i = 0; i < len; ++i) { + uart_tx_one_char(str[i]); + } + MP_THREAD_GIL_ENTER(); + mp_uos_dupterm_tx_strn(str, len); +} + +// Efficiently convert "\n" to "\r\n" +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { + const char *last = str; + while (len--) { + if (*str == '\n') { + if (str > last) { + mp_hal_stdout_tx_strn(last, str - last); + } + mp_hal_stdout_tx_strn("\r\n", 2); + ++str; + last = str; + } else { + ++str; + } + } + if (str > last) { + mp_hal_stdout_tx_strn(last, str - last); + } +} + +uint32_t mp_hal_ticks_ms(void) { + return esp_timer_get_time() / 1000; +} + +uint32_t mp_hal_ticks_us(void) { + return esp_timer_get_time(); +} + +void mp_hal_delay_ms(uint32_t ms) { + uint64_t us = ms * 1000; + uint64_t dt; + uint64_t t0 = esp_timer_get_time(); + for (;;) { + uint64_t t1 = esp_timer_get_time(); + dt = t1 - t0; + if (dt + portTICK_PERIOD_MS * 1000 >= us) { + // doing a vTaskDelay would take us beyond requested delay time + break; + } + MICROPY_EVENT_POLL_HOOK + vTaskDelay(1); + } + if (dt < us) { + // do the remaining delay accurately + mp_hal_delay_us(us - dt); + } +} + +void mp_hal_delay_us(uint32_t us) { + // these constants are tested for a 240MHz clock + const uint32_t this_overhead = 5; + const uint32_t pend_overhead = 150; + + // return if requested delay is less than calling overhead + if (us < this_overhead) { + return; + } + us -= this_overhead; + + uint64_t t0 = esp_timer_get_time(); + for (;;) { + uint64_t dt = esp_timer_get_time() - t0; + if (dt >= us) { + return; + } + if (dt + pend_overhead < us) { + // we have enough time to service pending events + // (don't use MICROPY_EVENT_POLL_HOOK because it also yields) + mp_handle_pending(); + } + } +} + +// this function could do with improvements (eg use ets_delay_us) +void mp_hal_delay_us_fast(uint32_t us) { + uint32_t delay = ets_get_cpu_frequency() / 19; + while (--us) { + for (volatile uint32_t i = delay; i; --i) { + } + } +} + +/* +extern int mp_stream_errno; +int *__errno() { + return &mp_stream_errno; +} +*/ diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h new file mode 100644 index 0000000000..3215bc062c --- /dev/null +++ b/ports/esp32/mphalport.h @@ -0,0 +1,86 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef INCLUDED_MPHALPORT_H +#define INCLUDED_MPHALPORT_H + +#include "py/ringbuf.h" +#include "lib/utils/interrupt_char.h" + +extern ringbuf_t stdin_ringbuf; + +uint32_t mp_hal_ticks_us(void); +__attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) { + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + return ccount; +} + +void mp_hal_delay_us(uint32_t); +void mp_hal_delay_us_fast(uint32_t); +void mp_hal_set_interrupt_char(int c); +uint32_t mp_hal_get_cpu_freq(void); + +#define mp_hal_quiet_timing_enter() MICROPY_BEGIN_ATOMIC_SECTION() +#define mp_hal_quiet_timing_exit(irq_state) MICROPY_END_ATOMIC_SECTION(irq_state) + +// C-level pin HAL +#include "py/obj.h" +#include "driver/gpio.h" +#define MP_HAL_PIN_FMT "%u" +#define mp_hal_pin_obj_t gpio_num_t +mp_hal_pin_obj_t machine_pin_get_id(mp_obj_t pin_in); +#define mp_hal_get_pin_obj(o) machine_pin_get_id(o) +#define mp_obj_get_pin(o) machine_pin_get_id(o) // legacy name; only to support esp8266/modonewire +#define mp_hal_pin_name(p) (p) +static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) { + gpio_pad_select_gpio(pin); + gpio_set_direction(pin, GPIO_MODE_INPUT); +} +static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) { + gpio_pad_select_gpio(pin); + gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT); +} +static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) { + gpio_pad_select_gpio(pin); + gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT_OD); +} +static inline void mp_hal_pin_od_low(mp_hal_pin_obj_t pin) { + gpio_set_level(pin, 0); +} +static inline void mp_hal_pin_od_high(mp_hal_pin_obj_t pin) { + gpio_set_level(pin, 1); +} +static inline int mp_hal_pin_read(mp_hal_pin_obj_t pin) { + return gpio_get_level(pin); +} +static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) { + gpio_set_level(pin, v); +} + +#endif // INCLUDED_MPHALPORT_H diff --git a/ports/esp32/mpthreadport.c b/ports/esp32/mpthreadport.c new file mode 100644 index 0000000000..76d9431c03 --- /dev/null +++ b/ports/esp32/mpthreadport.c @@ -0,0 +1,226 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * Copyright (c) 2017 Pycom Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "stdio.h" + +#include "py/mpconfig.h" +#include "py/mpstate.h" +#include "py/gc.h" +#include "py/mpthread.h" +#include "mpthreadport.h" + +#include "esp_task.h" + +#if MICROPY_PY_THREAD + +#define MP_THREAD_MIN_STACK_SIZE (4 * 1024) +#define MP_THREAD_DEFAULT_STACK_SIZE (MP_THREAD_MIN_STACK_SIZE + 1024) +#define MP_THREAD_PRIORITY (ESP_TASK_PRIO_MIN + 1) + +// this structure forms a linked list, one node per active thread +typedef struct _thread_t { + TaskHandle_t id; // system id of thread + int ready; // whether the thread is ready and running + void *arg; // thread Python args, a GC root pointer + void *stack; // pointer to the stack + StaticTask_t *tcb; // pointer to the Task Control Block + size_t stack_len; // number of words in the stack + struct _thread_t *next; +} thread_t; + +// the mutex controls access to the linked list +STATIC mp_thread_mutex_t thread_mutex; +STATIC thread_t thread_entry0; +STATIC thread_t *thread; // root pointer, handled by mp_thread_gc_others + +void mp_thread_init(void *stack, uint32_t stack_len) { + mp_thread_set_state(&mp_state_ctx.thread); + // create the first entry in the linked list of all threads + thread = &thread_entry0; + thread->id = xTaskGetCurrentTaskHandle(); + thread->ready = 1; + thread->arg = NULL; + thread->stack = stack; + thread->stack_len = stack_len; + thread->next = NULL; + mp_thread_mutex_init(&thread_mutex); +} + +void mp_thread_gc_others(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + gc_collect_root((void**)&th, 1); + gc_collect_root(&th->arg, 1); // probably not needed + if (th->id == xTaskGetCurrentTaskHandle()) { + continue; + } + if (!th->ready) { + continue; + } + gc_collect_root(th->stack, th->stack_len); // probably not needed + } + mp_thread_mutex_unlock(&thread_mutex); +} + +mp_state_thread_t *mp_thread_get_state(void) { + return pvTaskGetThreadLocalStoragePointer(NULL, 1); +} + +void mp_thread_set_state(void *state) { + vTaskSetThreadLocalStoragePointer(NULL, 1, state); +} + +void mp_thread_start(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 1; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +STATIC void *(*ext_thread_entry)(void*) = NULL; + +STATIC void freertos_entry(void *arg) { + if (ext_thread_entry) { + ext_thread_entry(arg); + } + vTaskDelete(NULL); + for (;;); +} + +void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) { + // store thread entry function into a global variable so we can access it + ext_thread_entry = entry; + + if (*stack_size == 0) { + *stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size + } else if (*stack_size < MP_THREAD_MIN_STACK_SIZE) { + *stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size + } + + // allocate TCB, stack and linked-list node (must be outside thread_mutex lock) + StaticTask_t *tcb = m_new(StaticTask_t, 1); + StackType_t *stack = m_new(StackType_t, *stack_size / sizeof(StackType_t)); + thread_t *th = m_new_obj(thread_t); + + mp_thread_mutex_lock(&thread_mutex, 1); + + // create thread + TaskHandle_t id = xTaskCreateStaticPinnedToCore(freertos_entry, name, *stack_size / sizeof(StackType_t), arg, priority, stack, tcb, 0); + if (id == NULL) { + mp_thread_mutex_unlock(&thread_mutex); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); + } + + // adjust the stack_size to provide room to recover from hitting the limit + *stack_size -= 1024; + + // add thread to linked list of all threads + th->id = id; + th->ready = 0; + th->arg = arg; + th->stack = stack; + th->tcb = tcb; + th->stack_len = *stack_size / sizeof(StackType_t); + th->next = thread; + thread = th; + + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { + mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, "mp_thread"); +} + +void mp_thread_finish(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + if (th->id == xTaskGetCurrentTaskHandle()) { + th->ready = 0; + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void vPortCleanUpTCB(void *tcb) { + thread_t *prev = NULL; + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; prev = th, th = th->next) { + // unlink the node from the list + if (th->tcb == tcb) { + if (prev != NULL) { + prev->next = th->next; + } else { + // move the start pointer + thread = th->next; + } + // explicitly release all its memory + m_del(StaticTask_t, th->tcb, 1); + m_del(StackType_t, th->stack, th->stack_len); + m_del(thread_t, th, 1); + break; + } + } + mp_thread_mutex_unlock(&thread_mutex); +} + +void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { + mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer); +} + +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { + return (pdTRUE == xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0)); +} + +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { + xSemaphoreGive(mutex->handle); +} + +void mp_thread_deinit(void) { + mp_thread_mutex_lock(&thread_mutex, 1); + for (thread_t *th = thread; th != NULL; th = th->next) { + // don't delete the current task + if (th->id == xTaskGetCurrentTaskHandle()) { + continue; + } + vTaskDelete(th->id); + } + mp_thread_mutex_unlock(&thread_mutex); + // allow FreeRTOS to clean-up the threads + vTaskDelay(2); +} + +#else + +void vPortCleanUpTCB(void *tcb) { +} + +#endif // MICROPY_PY_THREAD diff --git a/ports/esp32/mpthreadport.h b/ports/esp32/mpthreadport.h new file mode 100644 index 0000000000..54e35d61c3 --- /dev/null +++ b/ports/esp32/mpthreadport.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd + * Copyright (c) 2017 Pycom Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ESP32_MPTHREADPORT_H +#define MICROPY_INCLUDED_ESP32_MPTHREADPORT_H + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" + +typedef struct _mp_thread_mutex_t { + SemaphoreHandle_t handle; + StaticSemaphore_t buffer; +} mp_thread_mutex_t; + +void mp_thread_init(void *stack, uint32_t stack_len); +void mp_thread_gc_others(void); +void mp_thread_deinit(void); + +#endif // MICROPY_INCLUDED_ESP32_MPTHREADPORT_H diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c new file mode 100644 index 0000000000..fba4de73ab --- /dev/null +++ b/ports/esp32/network_lan.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * + * Based on the ESP IDF example code which is Public Domain / CC0 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" + +#include "eth_phy/phy.h" +#include "eth_phy/phy_tlk110.h" +#include "eth_phy/phy_lan8720.h" +#include "tcpip_adapter.h" + +#include "modnetwork.h" + +typedef struct _lan_if_obj_t { + mp_obj_base_t base; + int if_id; // MUST BE FIRST to match wlan_if_obj_t + bool initialized; + bool active; + uint8_t mdc_pin; + uint8_t mdio_pin; + int8_t phy_power_pin; + uint8_t phy_addr; + uint8_t phy_type; + eth_phy_check_link_func link_func; + eth_phy_power_enable_func power_func; +} lan_if_obj_t; + +const mp_obj_type_t lan_if_type; +STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false}; + +STATIC void phy_power_enable(bool enable) { + lan_if_obj_t* self = &lan_obj; + + if (self->phy_power_pin != -1) { + + if (!enable) { + // Do the PHY-specific power_enable(false) function before powering down + self->power_func(false); + } + + gpio_pad_select_gpio(self->phy_power_pin); + gpio_set_direction(self->phy_power_pin, GPIO_MODE_OUTPUT); + if (enable) { + gpio_set_level(self->phy_power_pin, 1); + } else { + gpio_set_level(self->phy_power_pin, 0); + } + + // Allow the power up/down to take effect, min 300us + vTaskDelay(1); + + if (enable) { + // Run the PHY-specific power on operations now the PHY has power + self->power_func(true); + } + } +} + +STATIC void init_lan_rmii() { + lan_if_obj_t* self = &lan_obj; + phy_rmii_configure_data_interface_pins(); + phy_rmii_smi_configure_pins(self->mdc_pin, self->mdio_pin); +} + +STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + lan_if_obj_t* self = &lan_obj; + + if (self->initialized) { + return MP_OBJ_FROM_PTR(&lan_obj); + } + + enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_id].u_obj != mp_const_none) { + if (mp_obj_get_int(args[ARG_id].u_obj) != 0) { + mp_raise_ValueError("invalid LAN interface identifier"); + } + } + + self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj); + self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj); + self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj); + + if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) { + mp_raise_ValueError("invalid phy address"); + } + + if (args[ARG_phy_type].u_int != PHY_LAN8720 && args[ARG_phy_type].u_int != PHY_TLK110) { + mp_raise_ValueError("invalid phy type"); + } + + eth_config_t config; + + switch (args[ARG_phy_type].u_int) { + case PHY_TLK110: + config = phy_tlk110_default_ethernet_config; + break; + case PHY_LAN8720: + config = phy_lan8720_default_ethernet_config; + break; + } + + self->link_func = config.phy_check_link; + + // Replace default power func with our own + self->power_func = config.phy_power_enable; + config.phy_power_enable = phy_power_enable; + + config.phy_addr = args[ARG_phy_addr].u_int; + config.gpio_config = init_lan_rmii; + config.tcpip_input = tcpip_adapter_eth_input; + + if (esp_eth_init(&config) == ESP_OK) { + self->active = false; + self->initialized = true; + } else { + mp_raise_msg(&mp_type_OSError, "esp_eth_init() failed"); + } + return MP_OBJ_FROM_PTR(&lan_obj); +} +MP_DEFINE_CONST_FUN_OBJ_KW(get_lan_obj, 0, get_lan); + +STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) { + lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (n_args > 1) { + if (mp_obj_is_true(args[1])) { + self->active = (esp_eth_enable() == ESP_OK); + if (!self->active) { + mp_raise_msg(&mp_type_OSError, "ethernet enable failed"); + } + } else { + self->active = !(esp_eth_disable() == ESP_OK); + if (self->active) { + mp_raise_msg(&mp_type_OSError, "ethernet disable failed"); + } + } + } + return mp_obj_new_bool(self->active); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lan_active_obj, 1, 2, lan_active); + +STATIC mp_obj_t lan_status(mp_obj_t self_in) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_status_obj, lan_status); + +STATIC mp_obj_t lan_isconnected(mp_obj_t self_in) { + lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->active ? mp_obj_new_bool(self->link_func()) : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_isconnected_obj, lan_isconnected); + +STATIC const mp_rom_map_elem_t lan_if_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&lan_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&lan_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(lan_if_locals_dict, lan_if_locals_dict_table); + +const mp_obj_type_t lan_if_type = { + { &mp_type_type }, + .name = MP_QSTR_LAN, + .locals_dict = (mp_obj_dict_t*)&lan_if_locals_dict, +}; diff --git a/ports/esp32/partitions.csv b/ports/esp32/partitions.csv new file mode 100644 index 0000000000..98adcd20a7 --- /dev/null +++ b/ports/esp32/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 0x180000, diff --git a/ports/esp32/qstrdefsport.h b/ports/esp32/qstrdefsport.h new file mode 100644 index 0000000000..ff6c2cc426 --- /dev/null +++ b/ports/esp32/qstrdefsport.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// qstrs specific to this port, only needed if they aren't auto-generated + +// Entries for sys.path +Q(/lib) diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h new file mode 100644 index 0000000000..f85257a192 --- /dev/null +++ b/ports/esp32/sdkconfig.h @@ -0,0 +1,191 @@ +/* Start bootloader config */ +#define CONFIG_FLASHMODE_DIO 1 +#define CONFIG_ESPTOOLPY_FLASHFREQ_40M 1 +/* End bootloader config */ + +#define CONFIG_TRACEMEM_RESERVE_DRAM 0x0 +#define CONFIG_BT_RESERVE_DRAM 0x0 +#define CONFIG_ULP_COPROC_RESERVE_MEM 2040 +#define CONFIG_PHY_DATA_OFFSET 0xf000 +#define CONFIG_APP_OFFSET 0x10000 + +#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1 +#define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS 1 +#define CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS 4 + +#define CONFIG_BROWNOUT_DET 1 +#define CONFIG_BROWNOUT_DET_LVL 0 +#define CONFIG_BROWNOUT_DET_LVL_SEL_0 1 + +#define CONFIG_TCPIP_TASK_STACK_SIZE 2560 +#define CONFIG_TCPIP_RECVMBOX_SIZE 32 + +#define CONFIG_ESP32_APPTRACE_DEST_NONE 1 +#define CONFIG_ESP32_PHY_MAX_TX_POWER 20 +#define CONFIG_ESP32_PANIC_PRINT_REBOOT 1 +#define CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC 1 +#define CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES 100 +#define CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 1 +#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240 +#define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1 +#define CONFIG_ESP32_DEBUG_OCDAWARE 1 +#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000 +#define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1 +#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1 +#define CONFIG_ESP32_WIFI_AMPDU_ENABLED 1 +#define CONFIG_ESP32_WIFI_NVS_ENABLED 1 +#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 10 +#define CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 0 +#define CONFIG_ESP32_WIFI_TX_BUFFER_TYPE 1 +#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER 1 +#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32 +#define CONFIG_ESP32_WIFI_RX_BA_WIN 6 +#define CONFIG_ESP32_WIFI_TX_BA_WIN 6 +#define CONFIG_ESP32_XTAL_FREQ_AUTO 1 +#define CONFIG_ESP32_XTAL_FREQ 0 +#define CONFIG_ESP32_RTC_CLK_CAL_CYCLES 1024 +#define CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT 5 +#define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT 2048 + +#if CONFIG_SPIRAM_SUPPORT +#define CONFIG_SPIRAM_TYPE_ESPPSRAM32 1 +#define CONFIG_SPIRAM_SIZE 4194304 +#define CONFIG_SPIRAM_SPEED_40M 1 +#define CONFIG_SPIRAM_CACHE_WORKAROUND 1 +#define CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL 16384 +#define CONFIG_SPIRAM_BOOT_INIT 1 +#define CONFIG_SPIRAM_MEMTEST 1 +#define CONFIG_SPIRAM_USE_MALLOC 1 +#define CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL 32768 +#define CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY 1 +#endif + +#define CONFIG_FOUR_MAC_ADDRESS_FROM_EFUSE 1 +#define CONFIG_DMA_RX_BUF_NUM 10 +#define CONFIG_DMA_TX_BUF_NUM 10 +#define CONFIG_EMAC_TASK_PRIORITY 20 + +#define CONFIG_INT_WDT 1 +#define CONFIG_INT_WDT_TIMEOUT_MS 300 +#define CONFIG_INT_WDT_CHECK_CPU1 0 +#define CONFIG_TASK_WDT 1 +#define CONFIG_TASK_WDT_PANIC 1 +#define CONFIG_TASK_WDT_TIMEOUT_S 5 +#define CONFIG_TASK_WDT_CHECK_IDLE_TASK 0 +#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 0 + +#define CONFIG_FREERTOS_UNICORE 1 +#define CONFIG_FREERTOS_CORETIMER_0 1 +#define CONFIG_FREERTOS_HZ 100 +#define CONFIG_FREERTOS_ASSERT_FAIL_ABORT 1 +#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1 +#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE 1 +#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 2 +#define CONFIG_FREERTOS_IDLE_TASK_STACKSIZE 1024 +#define CONFIG_FREERTOS_ISR_STACKSIZE 1536 +#define CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG 1 +#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16 +#define CONFIG_SUPPORT_STATIC_ALLOCATION 1 +#define CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK 1 + +#define CONFIG_MAIN_TASK_STACK_SIZE 4096 +#define CONFIG_IPC_TASK_STACK_SIZE 1024 +#define CONFIG_BTC_TASK_STACK_SIZE 3072 +#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE 4096 +#define CONFIG_SYSTEM_EVENT_QUEUE_SIZE 32 +#define CONFIG_TIMER_TASK_STACK_SIZE 4096 +#define CONFIG_TIMER_TASK_PRIORITY 1 +#define CONFIG_TIMER_TASK_STACK_DEPTH 2048 +#define CONFIG_TIMER_QUEUE_LENGTH 10 + +#define CONFIG_NEWLIB_STDIN_LINE_ENDING_CR 1 +#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF 1 +#define CONFIG_PHY_ENABLED 1 +#define CONFIG_WIFI_ENABLED 1 +#define CONFIG_OPTIMIZATION_LEVEL_DEBUG 1 +#define CONFIG_MEMMAP_SMP 1 + +#define CONFIG_PARTITION_TABLE_SINGLE_APP 1 +#define CONFIG_PARTITION_TABLE_FILENAME "partitions_singleapp.csv" +#define CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET 0x10000 +#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv" + +#define CONFIG_CONSOLE_UART_BAUDRATE 115200 +#define CONFIG_CONSOLE_UART_NUM 0 +#define CONFIG_CONSOLE_UART_DEFAULT 1 + +#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1 +#define CONFIG_LOG_BOOTLOADER_LEVEL_WARN 1 +#define CONFIG_LOG_DEFAULT_LEVEL 3 +#define CONFIG_LOG_COLORS 1 +#define CONFIG_LOG_BOOTLOADER_LEVEL 2 + +#define CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX 0 +#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1 +#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1 +#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60 +#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8 +#define CONFIG_LWIP_MAX_ACTIVE_TCP 16 +#define CONFIG_LWIP_MAX_SOCKETS 8 +#define CONFIG_LWIP_SO_REUSE 1 +#define CONFIG_LWIP_ETHARP_TRUST_IP_MAC 1 +#define CONFIG_IP_LOST_TIMER_INTERVAL 120 +#define CONFIG_UDP_RECVMBOX_SIZE 6 +#define CONFIG_TCP_MAXRTX 12 +#define CONFIG_TCP_SYNMAXRTX 6 +#define CONFIG_TCP_MSL 60000 +#define CONFIG_TCP_MSS 1436 +#define CONFIG_TCP_SND_BUF_DEFAULT 5744 +#define CONFIG_TCP_WND_DEFAULT 5744 +#define CONFIG_TCP_QUEUE_OOSEQ 1 +#define CONFIG_TCP_OVERSIZE_MSS 1 +#define CONFIG_TCP_RECVMBOX_SIZE 6 + +#define CONFIG_MBEDTLS_AES_C 1 +#define CONFIG_MBEDTLS_CCM_C 1 +#define CONFIG_MBEDTLS_ECDH_C 1 +#define CONFIG_MBEDTLS_ECDSA_C 1 +#define CONFIG_MBEDTLS_ECP_C 1 +#define CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_NIST_OPTIM 1 +#define CONFIG_MBEDTLS_GCM_C 1 +#define CONFIG_MBEDTLS_HARDWARE_AES 1 +#define CONFIG_MBEDTLS_HAVE_TIME 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA 1 +#define CONFIG_MBEDTLS_PEM_PARSE_C 1 +#define CONFIG_MBEDTLS_PEM_WRITE_C 1 +#define CONFIG_MBEDTLS_RC4_DISABLED 1 +#define CONFIG_MBEDTLS_SSL_ALPN 1 +#define CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN 16384 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1 1 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_1 1 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 1 +#define CONFIG_MBEDTLS_SSL_RENEGOTIATION 1 +#define CONFIG_MBEDTLS_SSL_SESSION_TICKETS 1 +#define CONFIG_MBEDTLS_TLS_CLIENT 1 +#define CONFIG_MBEDTLS_TLS_ENABLED 1 +#define CONFIG_MBEDTLS_TLS_SERVER 1 +#define CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT 1 +#define CONFIG_MBEDTLS_X509_CRL_PARSE_C 1 +#define CONFIG_MBEDTLS_X509_CSR_PARSE_C 1 + +#define CONFIG_MAKE_WARN_UNDEFINED_VARIABLES 1 +#define CONFIG_TOOLPREFIX "xtensa-esp32-elf-" +#define CONFIG_PYTHON "python2" diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c new file mode 100644 index 0000000000..10a4ba462e --- /dev/null +++ b/ports/esp32/uart.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "driver/uart.h" + +#include "py/mpstate.h" +#include "py/mphal.h" + +STATIC void uart_irq_handler(void *arg); + +void uart_init(void) { + uart_isr_handle_t handle; + uart_isr_register(UART_NUM_0, uart_irq_handler, NULL, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, &handle); + uart_enable_rx_intr(UART_NUM_0); +} + +// all code executed in ISR must be in IRAM, and any const data must be in DRAM +STATIC void IRAM_ATTR uart_irq_handler(void *arg) { + volatile uart_dev_t *uart = &UART0; + uart->int_clr.rxfifo_full = 1; + uart->int_clr.frm_err = 1; + uart->int_clr.rxfifo_tout = 1; + while (uart->status.rxfifo_cnt) { + uint8_t c = uart->fifo.rw_byte; + if (c == mp_interrupt_char) { + // inline version of mp_keyboard_interrupt(); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)); + #if MICROPY_ENABLE_SCHEDULER + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { + MP_STATE_VM(sched_state) = MP_SCHED_PENDING; + } + #endif + } else { + // this is an inline function so will be in IRAM + ringbuf_put(&stdin_ringbuf, c); + } + } +} diff --git a/ports/esp32/uart.h b/ports/esp32/uart.h new file mode 100644 index 0000000000..264c8b8949 --- /dev/null +++ b/ports/esp32/uart.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_ESP32_UART_H +#define MICROPY_INCLUDED_ESP32_UART_H + +void uart_init(void); + +#endif // MICROPY_INCLUDED_ESP32_UART_H diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 8fabd3412a..5c0983fe7e 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -193,6 +193,7 @@ LIB_SRC_C += \ lib/oofatfs/option/unicode.c endif + bus/softspi.c \ SRC_S = \ gchelper.s \ @@ -205,7 +206,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) -#OBJ += $(BUILD)/pins_$(BOARD).o # List of sources for qstr extraction SRC_QSTR += $(SRC_C) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) $(STM_SRC_C) $(EXTMOD_SRC_C) $(DRIVERS_SRC_C) @@ -258,32 +258,6 @@ ota: rm -f $(BUILD)/firmware.elf $(BUILD)/firmware.elf*.bin $(MAKE) LDSCRIPT=esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin -#MAKE_PINS = boards/make-pins.py -#BOARD_PINS = boards/$(BOARD)/pins.csv -#AF_FILE = boards/stm32f4xx_af.csv -#PREFIX_FILE = boards/stm32f4xx_prefix.c -#GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c -#GEN_PINS_HDR = $(HEADER_BUILD)/pins.h -#GEN_PINS_QSTR = $(BUILD)/pins_qstr.h -#GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h -#GEN_PINS_AF_PY = $(BUILD)/pins_af.py - -# Making OBJ use an order-only depenedency on the generated pins.h file -# has the side effect of making the pins.h file before we actually compile -# any of the objects. The normal dependency generation will deal with the -# case when pins.h is modified. But when it doesn't exist, we don't know -# which source files might need it. -#$(OBJ): | $(HEADER_BUILD)/pins.h - -# Use a pattern rule here so that make will only call make-pins.py once to make -# both pins_$(BOARD).c and pins.h -#$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) -# $(ECHO) "Create $@" -# $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) -# -#$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c -# $(call compile_c) - include $(TOP)/py/mkrules.mk axtls: $(BUILD)/libaxtls.a diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md index 252e195d83..f4dddd1ca1 100644 --- a/ports/esp8266/README.md +++ b/ports/esp8266/README.md @@ -49,7 +49,7 @@ $ make -C mpy-cross Then, to build MicroPython for the ESP8266, just run: ```bash -$ cd esp8266 +$ cd ports/esp8266 $ make axtls $ make ``` @@ -92,12 +92,16 @@ of FlashROM. First start ----------- +Be sure to change ESP8266's WiFi access point password ASAP, see below. + __Serial prompt__ You can access the REPL (Python prompt) over UART (the same as used for programming). - Baudrate: 115200 +Run `help()` for some basic information. + __WiFi__ Initially, the device configures itself as a WiFi access point (AP). @@ -105,14 +109,32 @@ Initially, the device configures itself as a WiFi access point (AP). - Password: micropythoN (note the upper-case N). - IP address of the board: 192.168.4.1. - DHCP-server is activated. +- Please be sure to change the password to something non-guessable + immediately. `help()` gives information how. __WebREPL__ Python prompt over WiFi, connecting through a browser. - Hosted at http://micropython.org/webrepl. - GitHub repository https://github.com/micropython/webrepl. + Please follow the instructions there. -Please follow the instructions there. +__upip__ + +The ESP8266 port comes with builtin `upip` package manager, which can +be used to install additional modules (see the main README for more +information): + +``` +>>> import upip +>>> upip.install("micropython-pystone_lowmem") +[...] +>>> import pystone_lowmem +>>> pystone_lowmem.main() +``` + +Downloading and installing packages may requite a lot of free memory, +if you get an error, retry immediately after the hard reset. Documentation ------------- diff --git a/ports/esp8266/common-hal/os/__init__.c b/ports/esp8266/common-hal/os/__init__.c index d9d1da2662..b9773d1868 100644 --- a/ports/esp8266/common-hal/os/__init__.c +++ b/ports/esp8266/common-hal/os/__init__.c @@ -58,7 +58,7 @@ STATIC mp_obj_tuple_t os_uname_info_obj = { mp_obj_t common_hal_os_uname(void) { // We must populate the "release" field each time in case it was GC'd since the last call. const char *ver = system_get_sdk_version(); - os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver), false); + os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver)); return (mp_obj_t)&os_uname_info_obj; } @@ -75,6 +75,19 @@ bool common_hal_os_urandom(uint8_t* buffer, uint32_t length) { i++; new_random >>= 8; } +// We wrap the mp_uos_dupterm function to detect if a UART is attached or not +mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args) { + mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args); + if (mp_obj_get_type(args[0]) == &pyb_uart_type) { + ++uart_attached_to_dupterm; + } + if (mp_obj_get_type(prev_obj) == &pyb_uart_type) { + --uart_attached_to_dupterm; + } + return prev_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 1, 2, os_dupterm); + } return true; } diff --git a/ports/esp8266/esp8266_common.ld b/ports/esp8266/esp8266_common.ld index aeeecb9277..b247e3ffd4 100644 --- a/ports/esp8266/esp8266_common.ld +++ b/ports/esp8266/esp8266_common.ld @@ -139,6 +139,7 @@ SECTIONS *lib/netutils/*.o*(.literal*, .text*) *lib/timeutils/*.o*(.literal*, .text*) *lib/utils/*.o*(.literal*, .text*) + *drivers/bus/*.o(.literal* .text*) build/main.o(.literal* .text*) *gccollect.o(.literal* .text*) diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index 93ebc450a3..5dcdd6fba1 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -35,15 +35,18 @@ #include "extmod/misc.h" #include "lib/utils/pyexec.h" -STATIC byte input_buf_array[256]; -ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)}; +STATIC byte stdin_ringbuf_array[256]; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len); const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked}; +int uart_attached_to_dupterm; + void mp_hal_init(void) { //ets_wdt_disable(); // it's a pain while developing mp_hal_rtc_init(); uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200); + uart_attached_to_dupterm = 0; } void mp_hal_delay_us(uint32_t us) { @@ -59,7 +62,7 @@ uint32_t mp_hal_get_cpu_freq(void) { int mp_hal_stdin_rx_chr(void) { for (;;) { - int c = ringbuf_get(&input_buf); + int c = ringbuf_get(&stdin_ringbuf); if (c != -1) { return c; } @@ -84,19 +87,11 @@ void mp_hal_debug_str(const char *str) { #endif void mp_hal_stdout_tx_str(const char *str) { - const char *last = str; - while (*str) { - uart_tx_one_char(UART0, *str++); - } - mp_uos_dupterm_tx_strn(last, str - last); + mp_uos_dupterm_tx_strn(str, strlen(str)); } void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { - const char *last = str; - while (len--) { - uart_tx_one_char(UART0, *str++); - } - mp_uos_dupterm_tx_strn(last, str - last); + mp_uos_dupterm_tx_strn(str, len); } void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { @@ -106,13 +101,11 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { if (str > last) { mp_uos_dupterm_tx_strn(last, str - last); } - uart_tx_one_char(UART0, '\r'); - uart_tx_one_char(UART0, '\n'); mp_uos_dupterm_tx_strn("\r\n", 2); ++str; last = str; } else { - uart_tx_one_char(UART0, *str++); + ++str; } } if (str > last) { @@ -170,7 +163,7 @@ STATIC void dupterm_task_handler(os_event_t *evt) { if (c < 0) { break; } - ringbuf_put(&input_buf, c); + ringbuf_put(&stdin_ringbuf, c); } mp_hal_signal_input(); lock = 0; diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h index 194e56f649..56d9fa35fe 100644 --- a/ports/esp8266/esp_mphal.h +++ b/ports/esp8266/esp_mphal.h @@ -34,12 +34,15 @@ struct _mp_print_t; // Structure for UART-only output via mp_printf() extern const struct _mp_print_t mp_debug_print; -extern ringbuf_t input_buf; -// Call this after putting data to input_buf +extern ringbuf_t stdin_ringbuf; +// Call this after putting data to stdin_ringbuf void mp_hal_signal_input(void); // Call this when data is available in dupterm object void mp_hal_signal_dupterm_input(void); +// This variable counts how many times the UART is attached to dupterm +extern int uart_attached_to_dupterm; + void mp_hal_init(void); void mp_hal_rtc_init(void); @@ -86,7 +89,7 @@ void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin); } while (0) #define mp_hal_pin_od_high(p) do { \ if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); } \ - else { gpio_output_set(1 << (p), 0, 1 << (p), 0); } \ + else { gpio_output_set(0, 0, 0, 1 << (p)); /* set as input to avoid glitches */ } \ } while (0) #define mp_hal_pin_read(p) pin_get(p) #define mp_hal_pin_write(p, v) pin_set((p), (v)) diff --git a/ports/esp8266/esppwm.c b/ports/esp8266/esppwm.c index f1d7060dfe..33eaf3b9a1 100644 --- a/ports/esp8266/esppwm.c +++ b/ports/esp8266/esppwm.c @@ -190,11 +190,8 @@ pwm_start(void) // start gpio_output_set(local_single[0].gpio_set, local_single[0].gpio_clear, pwm_gpio, 0); - // yeah, if all channels' duty is 0 or 255, don't need to start timer, otherwise start... - if (*local_channel != 1) { - pwm_timer_down = 0; - RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time); - } + pwm_timer_down = 0; + RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time); } if (pwm_toggle == 1) { @@ -210,12 +207,12 @@ pwm_start(void) /****************************************************************************** * FunctionName : pwm_set_duty * Description : set each channel's duty params - * Parameters : uint8 duty : 0 ~ PWM_DEPTH + * Parameters : int16_t duty : 0 ~ PWM_DEPTH * uint8 channel : channel index * Returns : NONE *******************************************************************************/ void ICACHE_FLASH_ATTR -pwm_set_duty(uint16 duty, uint8 channel) +pwm_set_duty(int16_t duty, uint8 channel) { uint8 i; for(i=0;i= timeout_us) { @@ -201,7 +214,7 @@ bool uart_rx_wait(uint32_t timeout_us) { } int uart_rx_any(uint8 uart) { - if (input_buf.iget != input_buf.iput) { + if (uart_ringbuf.iget != uart_ringbuf.iput) { return true; // have at least 1 char ready for reading } return false; @@ -217,7 +230,7 @@ int uart_tx_any_room(uint8 uart) { // Returns char from the input buffer, else -1 if buffer is empty. int uart_rx_char(void) { - return ringbuf_get(&input_buf); + return ringbuf_get(&uart_ringbuf); } int uart_rx_one_char(uint8 uart_no) { @@ -276,7 +289,7 @@ void uart_task_handler(os_event_t *evt) { int c, ret = 0; while ((c = ringbuf_get(&input_buf)) >= 0) { - if (c == interrupt_char) { + if (c == mp_interrupt_char) { mp_keyboard_interrupt(); } ret = pyexec_event_repl_process_char(c); diff --git a/ports/esp8266/machine_hspi.c b/ports/esp8266/machine_hspi.c index 9fd0f48682..07770c8c89 100644 --- a/ports/esp8266/machine_hspi.c +++ b/ports/esp8266/machine_hspi.c @@ -39,6 +39,8 @@ #include "modmachine.h" #include "hspi.h" +#if MICROPY_PY_MACHINE_SPI + typedef struct _machine_hspi_obj_t { mp_obj_base_t base; uint32_t baudrate; @@ -65,6 +67,9 @@ STATIC void machine_hspi_transfer(mp_obj_base_t *self_in, size_t len, const uint spi_tx8fast(HSPI, src[i]); ++i; } + // wait for SPI transaction to complete + while (spi_busy(HSPI)) { + } } else { // we need to read and write data @@ -177,3 +182,5 @@ const mp_obj_type_t machine_hspi_type = { .protocol = &machine_hspi_p, .locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict, }; + +#endif // MICROPY_PY_MACHINE_SPI diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index c590ab59eb..da41b00c94 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -111,9 +111,29 @@ STATIC void mp_reset(void) { readline_init0(); dupterm_task_init(); pwmout_reset(); + + // Check if there are any dupterm objects registered and if not then + // activate UART(0), or else there will never be any chance to get a REPL + size_t idx; + for (idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + if (MP_STATE_VM(dupterm_objs[idx]) != MP_OBJ_NULL) { + break; + } + } + if (idx == MICROPY_PY_OS_DUPTERM) { + mp_obj_t args[2]; + args[0] = MP_OBJ_NEW_SMALL_INT(0); + args[1] = MP_OBJ_NEW_SMALL_INT(115200); + args[0] = pyb_uart_type.make_new(&pyb_uart_type, 2, 0, args); + args[1] = MP_OBJ_NEW_SMALL_INT(1); + extern mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args); + os_dupterm(2, args); + mp_hal_stdout_tx_str("Activated UART(0) for REPL\r\n"); + } } bool soft_reset(void) { + gc_sweep_all(); mp_hal_stdout_tx_str("PYB: soft reboot\r\n"); mp_hal_delay_us(10000); // allow UART to flush output mp_reset(); @@ -177,3 +197,17 @@ void __assert(const char *file, int line, const char *expr) { for (;;) { } } + +#if !MICROPY_DEBUG_PRINTERS +// With MICROPY_DEBUG_PRINTERS disabled DEBUG_printf is not defined but it +// is still needed by esp-open-lwip for debugging output, so define it here. +#include +int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args); +int DEBUG_printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int ret = mp_vprintf(&MICROPY_DEBUG_PRINTER_DEST, fmt, ap); + va_end(ap); + return ret; +} +#endif diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c index 99286848e2..7e5f6714bf 100644 --- a/ports/esp8266/modmachine.c +++ b/ports/esp8266/modmachine.c @@ -255,8 +255,12 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) }, { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, + #if MICROPY_PY_MACHINE_I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, + #endif + #if MICROPY_PY_MACHINE_SPI { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hspi_type) }, + #endif // wake abilities { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index ff2172d422..e220808b11 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -65,6 +65,9 @@ STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) { int idx = 0; if (n_args > 0) { idx = mp_obj_get_int(args[0]); + if (idx < 0 || idx >= sizeof(wlan_objs)) { + mp_raise_ValueError(NULL); + } } return MP_OBJ_FROM_PTR(&wlan_objs[idx]); } @@ -150,14 +153,26 @@ STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); -STATIC mp_obj_t esp_status(mp_obj_t self_in) { - wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->if_id == STATION_IF) { - return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status()); +STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // Get link status + if (self->if_id == STATION_IF) { + return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status()); + } + return MP_OBJ_NEW_SMALL_INT(-1); + } else { + // Get specific status parameter + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_rssi: + if (self->if_id == STATION_IF) { + return MP_OBJ_NEW_SMALL_INT(wifi_station_get_rssi()); + } + } + mp_raise_ValueError("unknown status param"); } - return MP_OBJ_NEW_SMALL_INT(-1); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status); STATIC mp_obj_t *esp_scan_list = NULL; @@ -402,42 +417,45 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs mp_obj_t val; - #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) - switch ((uintptr_t)args[1]) { - case QS(MP_QSTR_mac): { + qstr key = mp_obj_str_get_qstr(args[1]); + switch (key) { + case MP_QSTR_mac: { uint8_t mac[6]; wifi_get_macaddr(self->if_id, mac); return mp_obj_new_bytes(mac, sizeof(mac)); } - case QS(MP_QSTR_essid): + case MP_QSTR_essid: if (self->if_id == STATION_IF) { val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid), false); } else { val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len, false); } break; - case QS(MP_QSTR_hidden): + case MP_QSTR_hidden: req_if = SOFTAP_IF; val = mp_obj_new_bool(cfg.ap.ssid_hidden); break; - case QS(MP_QSTR_authmode): + case MP_QSTR_authmode: req_if = SOFTAP_IF; val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode); break; - case QS(MP_QSTR_channel): + case MP_QSTR_channel: req_if = SOFTAP_IF; val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); break; - case QS(MP_QSTR_dhcp_hostname): { + case MP_QSTR_dhcp_hostname: { req_if = STATION_IF; char* s = wifi_station_get_hostname(); - val = mp_obj_new_str(s, strlen(s), false); + if (s == NULL) { + val = MP_OBJ_NEW_QSTR(MP_QSTR_); + } else { + val = mp_obj_new_str(s, strlen(s)); + } break; } default: goto unknown; } - #undef QS // We post-check interface requirements to save on code size if (req_if >= 0) { diff --git a/ports/esp8266/modules/inisetup.py b/ports/esp8266/modules/inisetup.py index 46f0892484..7aa8bd4353 100644 --- a/ports/esp8266/modules/inisetup.py +++ b/ports/esp8266/modules/inisetup.py @@ -48,6 +48,8 @@ def setup(): # This file is executed on every boot (including wake-boot from deepsleep) #import esp #esp.osdebug(None) +import uos, machine +uos.dupterm(machine.UART(0, 115200), 1) import gc #import webrepl #webrepl.start() diff --git a/ports/esp8266/modules/ntptime.py b/ports/esp8266/modules/ntptime.py index a97e08e60d..85c754af6c 100644 --- a/ports/esp8266/modules/ntptime.py +++ b/ports/esp8266/modules/ntptime.py @@ -33,4 +33,3 @@ def settime(): tm = utime.localtime(t) tm = tm[0:3] + (0,) + tm[3:6] + (0,) machine.RTC().datetime(tm) - print(utime.localtime()) diff --git a/ports/esp8266/modules/webrepl_setup.py b/ports/esp8266/modules/webrepl_setup.py index 50d866b557..00b7c89e6e 100644 --- a/ports/esp8266/modules/webrepl_setup.py +++ b/ports/esp8266/modules/webrepl_setup.py @@ -34,12 +34,6 @@ def exists(fname): except OSError: return False -def copy_stream(s_in, s_out): - buf = bytearray(64) - while 1: - sz = s_in.readinto(buf) - s_out.write(buf, sz) - def get_daemon_status(): with open(RC) as f: @@ -50,22 +44,22 @@ def get_daemon_status(): return True return None -def add_daemon(): - with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: - new_f.write("import webrepl\nwebrepl.start()\n") - copy_stream(old_f, new_f) def change_daemon(action): LINES = ("import webrepl", "webrepl.start()") with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + found = False for l in old_f: for patt in LINES: if patt in l: + found = True if action and l.startswith("#"): l = l[1:] elif not action and not l.startswith("#"): l = "#" + l new_f.write(l) + if not found: + new_f.write("import webrepl\nwebrepl.start()\n") # FatFs rename() is not POSIX compliant, will raise OSError if # dest file exists. os.remove(RC) diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 907a4cbdfd..84c18f996b 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -30,6 +30,7 @@ #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_USE_INTERNAL_ERRNO (0) #define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_PY_DESCRIPTORS (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) @@ -40,7 +41,7 @@ #define MICROPY_PY_BUILTINS_SLICE (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_BUILTINS_PROPERTY (1) -#define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_BUILTINS_INPUT (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_TEXT esp_help_text @@ -51,10 +52,12 @@ #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_NONSTANDARD_TYPECODES (0) #define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH (0) #define MICROPY_PY_CMATH (0) #define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_IOBASE (1) #define MICROPY_PY_IO_FILEIO (1) #define MICROPY_PY_STRUCT (0) #define MICROPY_PY_SYS (1) @@ -87,7 +90,7 @@ #define MICROPY_PY_WEBREPL_DELAY (20) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) -#define MICROPY_PY_OS_DUPTERM (1) +#define MICROPY_PY_OS_DUPTERM (2) #define MICROPY_CPYTHON_COMPAT (0) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) @@ -142,8 +145,8 @@ typedef uint32_t sys_prot_t; // for modlwip void *esp_native_code_commit(void*, size_t); #define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len) -#define mp_type_fileio fatfs_type_fileio -#define mp_type_textio fatfs_type_textio +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio // use vfs's functions for import stat and builtin open #define mp_import_stat mp_vfs_import_stat diff --git a/ports/esp8266/mpconfigport_512k.h b/ports/esp8266/mpconfigport_512k.h index b84c134792..dc97efd35d 100644 --- a/ports/esp8266/mpconfigport_512k.h +++ b/ports/esp8266/mpconfigport_512k.h @@ -5,6 +5,9 @@ #undef MICROPY_EMIT_INLINE_XTENSA #define MICROPY_EMIT_INLINE_XTENSA (0) +#undef MICROPY_DEBUG_PRINTERS +#define MICROPY_DEBUG_PRINTERS (0) + #undef MICROPY_ERROR_REPORTING #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) diff --git a/ports/esp8266/posix_helpers.c b/ports/esp8266/posix_helpers.c index 1c20c8b0b1..adb0145e7d 100644 --- a/ports/esp8266/posix_helpers.c +++ b/ports/esp8266/posix_helpers.c @@ -55,14 +55,13 @@ void *realloc(void *ptr, size_t size) { return p; } -#define PLATFORM_HTONL(_n) ((uint32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) )) #undef htonl #undef ntohl uint32_t ntohl(uint32_t netlong) { - return PLATFORM_HTONL(netlong); + return MP_BE32TOH(netlong); } uint32_t htonl(uint32_t netlong) { - return PLATFORM_HTONL(netlong); + return MP_HTOBE32(netlong); } time_t time(time_t *t) { diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile index ae295d655e..64ad3cc0b2 100644 --- a/ports/minimal/Makefile +++ b/ports/minimal/Makefile @@ -41,13 +41,14 @@ LIBS = SRC_C = \ main.c \ uart_core.c \ + lib/utils/printf.c \ lib/utils/stdout_helpers.c \ lib/utils/pyexec.c \ lib/libc/string0.c \ lib/mp-readline/readline.c \ $(BUILD)/_frozen_mpy.c \ -OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) ifeq ($(CROSS), 1) all: $(BUILD)/firmware.dfu diff --git a/ports/minimal/README.md b/ports/minimal/README.md index 14b8c00a30..356fc4b3ef 100644 --- a/ports/minimal/README.md +++ b/ports/minimal/README.md @@ -9,7 +9,7 @@ By default the port will be built for the host machine: $ make -To run a small test script do: +To run the executable and get a basic working REPL do: $ make run diff --git a/ports/minimal/main.c b/ports/minimal/main.c index 9d43a9cf97..5e145dc829 100644 --- a/ports/minimal/main.c +++ b/ports/minimal/main.c @@ -27,7 +27,9 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { #endif static char *stack_top; +#if MICROPY_ENABLE_GC static char heap[2048]; +#endif int main(int argc, char **argv) { int stack_dummy; diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index 39e13853f4..95f349beba 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -9,10 +9,12 @@ include $(TOP)/py/py.mk CROSS_COMPILE = arm-none-eabi- +TINYTEST = $(TOP)/lib/tinytest + INC += -I. INC += -I$(TOP) INC += -I$(BUILD) -INC += -I$(TOP)/tools/tinytest/ +INC += -I$(TINYTEST) CFLAGS_CORTEX_M3 = -mthumb -mcpu=cortex-m3 -mfloat-abi=soft CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(CFLAGS_CORTEX_M3) $(COPT) \ @@ -44,7 +46,7 @@ SRC_RUN_C = \ SRC_TEST_C = \ test_main.c \ -LIB_SRC_C = $(addprefix lib/,\ +LIB_SRC_C += $(addprefix lib/,\ libm/math.c \ libm/fmodf.c \ libm/nearbyintf.c \ @@ -89,27 +91,9 @@ all: run run: $(BUILD)/firmware.elf qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware.elf -test: $(BUILD)/firmware-test.elf - qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware-test.elf > $(BUILD)/console.out - $(Q)tail -n2 $(BUILD)/console.out - $(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0" - -.PHONY: $(BUILD)/genhdr/tests.h - -$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h -$(BUILD)/genhdr/tests.h: - $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@ - -$(BUILD)/tinytest.o: - $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TOP)/tools/tinytest/tinytest.c - ## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here. $(BUILD)/firmware.elf: $(OBJ_COMMON) $(OBJ_RUN) $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ -$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST) - $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) - $(Q)$(SIZE) $@ - include $(TOP)/py/mkrules.mk diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test new file mode 100644 index 0000000000..a9aace6d07 --- /dev/null +++ b/ports/qemu-arm/Makefile.test @@ -0,0 +1,24 @@ +LIB_SRC_C = lib/upytesthelper/upytesthelper.c + +include Makefile + +CFLAGS += -DTEST + +.PHONY: $(BUILD)/genhdr/tests.h + +$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h +$(BUILD)/genhdr/tests.h: + (cd $(TOP)/tests; ./run-tests --write-exp) + $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@ + +$(BUILD)/tinytest.o: + $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c + +$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST) + $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +test: $(BUILD)/firmware-test.elf + qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware-test.elf > $(BUILD)/console.out + $(Q)tail -n2 $(BUILD)/console.out + $(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0" diff --git a/ports/qemu-arm/README.md b/ports/qemu-arm/README.md index 0cf93c7d56..4f1e79b101 100644 --- a/ports/qemu-arm/README.md +++ b/ports/qemu-arm/README.md @@ -21,3 +21,7 @@ toolchain and not with CodeSourcery toolchain. You will need to modify The difference is that CodeSourcery needs `-T generic-m-hosted.ld` while ARM's version requires `--specs=nano.specs --specs=rdimon.specs` to be passed to the linker. + +To build and run image with builtin testsuite: + + make -f Makefile.test test diff --git a/ports/qemu-arm/mpconfigport.h b/ports/qemu-arm/mpconfigport.h index 1998837846..dbfc395af2 100644 --- a/ports/qemu-arm/mpconfigport.h +++ b/ports/qemu-arm/mpconfigport.h @@ -17,6 +17,7 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_WARNINGS (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) @@ -70,3 +71,9 @@ extern const struct _mp_obj_module_t mp_module_uos; // We need to provide a declaration/definition of alloca() #include + +#ifdef TEST +#include "lib/upytesthelper/upytesthelper.h" +#undef MP_PLAT_PRINT_STRN +#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len) +#endif diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c index c018ae4285..adbdf04e18 100644 --- a/ports/qemu-arm/test_main.c +++ b/ports/qemu-arm/test_main.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "py/obj.h" #include "py/compile.h" @@ -17,44 +18,15 @@ #define HEAP_SIZE (128 * 1024) STATIC void *heap; -void do_str(const char *src); -inline void do_str(const char *src) { - gc_init(heap, (char*)heap + HEAP_SIZE); - mp_init(); - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - qstr source_name = lex->source_name; - mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); - mp_call_function_0(module_fun); - nlr_pop(); - } else { - mp_obj_t exc = (mp_obj_t)nlr.ret_val; - if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { - // Assume that sys.exit() is called to skip the test. - // TODO: That can be always true, we should set up convention to - // use specific exit code as skip indicator. - tinytest_set_test_skipped_(); - goto end; - } - mp_obj_print_exception(&mp_plat_print, exc); - tt_abort_msg("Uncaught exception"); - } -end: - mp_deinit(); -} - #include "genhdr/tests.h" int main() { - const char a[] = {"sim"}; mp_stack_ctrl_init(); mp_stack_set_limit(10240); heap = malloc(HEAP_SIZE); - int r = tinytest_main(1, (const char **) a, groups); - printf( "status: %i\n", r); + upytest_set_heap(heap, (char*)heap + HEAP_SIZE); + int r = tinytest_main(0, NULL, groups); + printf("status: %d\n", r); return r; } diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index a6e82b24d4..bedfa70091 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -14,6 +14,7 @@ include boards/$(BOARD)/mpconfigboard.mk # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h $(BUILD)/modstm_qstr.h +QSTR_GLOBAL_DEPENDENCIES = mpconfigboard_common.h boards/$(BOARD)/mpconfigboard.h # directory containing scripts to be frozen as bytecode FROZEN_MPY_DIR ?= modules @@ -37,6 +38,7 @@ DEVICE=0483:df11 STFLASH ?= st-flash OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg +STARTUP_FILE ?= boards/startup_stm32$(MCU_SERIES).o CROSS_COMPILE = arm-none-eabi- @@ -53,16 +55,22 @@ INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc CFLAGS_CORTEX_M = -mthumb # Select hardware floating-point support -ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx)) +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx STM32H743xx)) CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard else +ifeq ($(MCU_SERIES),f0) +CFLAGS_CORTEX_M += -msoft-float +else CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard endif +endif # Options for particular MCU series -CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_F4 -CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 -DMCU_SERIES_F7 -CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_L4 +CFLAGS_MCU_f0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0 -mcpu=cortex-m0 +CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 +CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) CFLAGS += -D$(CMSIS_MCU) @@ -70,6 +78,7 @@ CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) CFLAGS += $(COPT) CFLAGS += -Iboards/$(BOARD) CFLAGS += -DSTM32_HAL_H='' +CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR) ifeq ($(MICROPY_FLOAT_IMPL),double) CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE @@ -78,7 +87,7 @@ CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT CFLAGS += -fsingle-precision-constant -Wdouble-promotion endif -LDFLAGS = -nostdlib -L $(LD_DIR) -T $(LD_FILE) -Map=$(@:.elf=.map) --cref +LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) # Remove uncalled code from the final image. @@ -153,7 +162,6 @@ SRC_LIBM = $(addprefix lib/libm_dbl/,\ else SRC_LIBM = $(addprefix lib/libm/,\ math.c \ - thumb_vfp_sqrtf.c \ acoshf.c \ asinfacosf.c \ asinhf.c \ @@ -179,19 +187,27 @@ SRC_LIBM = $(addprefix lib/libm/,\ wf_lgamma.c \ wf_tgamma.c \ ) +ifeq ($(MCU_SERIES),f0) +SRC_LIBM += lib/libm/ef_sqrt.c +else +SRC_LIBM += lib/libm/thumb_vfp_sqrtf.c +endif endif EXTMOD_SRC_C = $(addprefix extmod/,\ + modlwip.c \ modonewire.c \ ) DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ + bus/softqspi.c \ memory/spiflash.c \ + dht/dht.c \ ) SRC_C = \ main.c \ - system_stm32.c \ stm32_it.c \ usbd_conf.c \ usbd_desc.c \ @@ -212,7 +228,9 @@ SRC_C = \ bufhelper.c \ dma.c \ i2c.c \ + pyb_i2c.c \ spi.c \ + qspi.c \ uart.c \ can.c \ usb.c \ @@ -232,6 +250,8 @@ SRC_C = \ rng.c \ rtc.c \ flash.c \ + flashbdev.c \ + spibdev.c \ storage.c \ sdcard.c \ fatfs_port.c \ @@ -242,15 +262,24 @@ SRC_C = \ adc.c \ $(wildcard boards/$(BOARD)/*.c) +ifeq ($(MCU_SERIES),f0) SRC_O = \ - startup_stm32.o \ - gchelper.o \ + $(STARTUP_FILE) \ + system_stm32f0.o \ + resethandler_m0.o \ + gchelper_m0.o +else +SRC_O = \ + $(STARTUP_FILE) \ + system_stm32.o \ + resethandler.o \ + gchelper.o +endif SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal.c \ hal_adc.c \ hal_adc_ex.c \ - hal_can.c \ hal_cortex.c \ hal_dac.c \ hal_dac_ex.c \ @@ -265,17 +294,27 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal_pwr_ex.c \ hal_rcc.c \ hal_rcc_ex.c \ - hal_rng.c \ hal_rtc.c \ hal_rtc_ex.c \ - hal_sd.c \ hal_spi.c \ hal_tim.c \ hal_tim_ex.c \ hal_uart.c \ + ) + +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l4)) +SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + hal_sd.c \ ll_sdmmc.c \ ll_usb.c \ ) +endif + +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx)) + SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c) +else + SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c) +endif SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\ core/src/usbd_core.c \ @@ -291,7 +330,7 @@ ifneq ($(MICROPY_PY_WIZNET5K),0) WIZNET5K_DIR=drivers/wiznet5k INC += -I$(TOP)/$(WIZNET5K_DIR) CFLAGS_MOD += -DMICROPY_PY_WIZNET5K=$(MICROPY_PY_WIZNET5K) -D_WIZCHIP_=$(MICROPY_PY_WIZNET5K) -SRC_MOD += modnwwiznet5k.c +SRC_MOD += network_wiznet5k.c modnwwiznet5k.c SRC_MOD += $(addprefix $(WIZNET5K_DIR)/,\ ethernet/w$(MICROPY_PY_WIZNET5K)/w$(MICROPY_PY_WIZNET5K).c \ ethernet/wizchip_conf.c \ @@ -323,6 +362,47 @@ SRC_MOD += $(addprefix $(CC3000_DIR)/src/,\ ) endif +LWIP_DIR = lib/lwip/src +INC += -I$(TOP)/$(LWIP_DIR)/include -Ilwip_inc +$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS += -Wno-address +SRC_MOD += $(addprefix $(LWIP_DIR)/,\ + core/def.c \ + core/dns.c \ + core/inet_chksum.c \ + core/init.c \ + core/ip.c \ + core/mem.c \ + core/memp.c \ + core/netif.c \ + core/pbuf.c \ + core/raw.c \ + core/stats.c \ + core/sys.c \ + core/tcp.c \ + core/tcp_in.c \ + core/tcp_out.c \ + core/timeouts.c \ + core/udp.c \ + core/ipv4/autoip.c \ + core/ipv4/dhcp.c \ + core/ipv4/etharp.c \ + core/ipv4/icmp.c \ + core/ipv4/igmp.c \ + core/ipv4/ip4_addr.c \ + core/ipv4/ip4.c \ + core/ipv4/ip4_frag.c \ + core/ipv6/dhcp6.c \ + core/ipv6/ethip6.c \ + core/ipv6/icmp6.c \ + core/ipv6/inet6.c \ + core/ipv6/ip6_addr.c \ + core/ipv6/ip6.c \ + core/ipv6/ip6_frag.c \ + core/ipv6/mld6.c \ + core/ipv6/nd6.c \ + netif/ethernet.c \ + ) + OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) @@ -336,6 +416,11 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) OBJ += $(BUILD)/pins_$(BOARD).o +# This file contains performance critical functions so turn up the optimisation +# level. It doesn't add much to the code size and improves performance a bit. +# Don't use -O3 with this file because gcc tries to optimise memset in terms of itself. +$(BUILD)/lib/libc/string0.o: COPT += -O2 + # We put several files into the first 16K section with the ISRs. # If we compile these using -O0 then it won't fit. So if you really want these # to be compiled with -O0, then edit boards/common.ld (in the .isr_vector section) @@ -376,27 +461,50 @@ else $(Q)$(DFU_UTIL) -a 0 -d $(DEVICE) -D $< endif -FLASH_ADDR ?= 0x08000000 -TEXT_ADDR ?= 0x08020000 +# A board should specify TEXT0_ADDR if to use a different location than the +# default for the firmware memory location. A board can also optionally define +# TEXT1_ADDR to split the firmware into two sections; see below for details. +TEXT0_ADDR ?= 0x08000000 + +ifeq ($(TEXT1_ADDR),) +# No TEXT1_ADDR given so put all firmware at TEXT0_ADDR location deploy-stlink: $(BUILD)/firmware.dfu - $(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK" - $(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(FLASH_ADDR) - $(ECHO) "Writing $(BUILD)/firmware1.bin to the board via ST-LINK" - $(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT_ADDR) + $(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK" + $(Q)$(STFLASH) write $(BUILD)/firmware.bin $(TEXT0_ADDR) deploy-openocd: $(BUILD)/firmware.dfu - $(ECHO) "Writing $(BUILD)/firmware{0,1}.bin to the board via ST-LINK using OpenOCD" - $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(FLASH_ADDR) $(BUILD)/firmware1.bin $(TEXT_ADDR)" + $(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK using OpenOCD" + $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware.bin $(TEXT0_ADDR)" $(BUILD)/firmware.dfu: $(BUILD)/firmware.elf $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware.bin $@ + +else +# TEXT0_ADDR and TEXT1_ADDR are specified so split firmware between these locations + +deploy-stlink: $(BUILD)/firmware.dfu + $(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK" + $(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(TEXT0_ADDR) + $(ECHO) "Writing $(BUILD)/firmware1.bin to the board via ST-LINK" + $(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT1_ADDR) + +deploy-openocd: $(BUILD)/firmware.dfu + $(ECHO) "Writing $(BUILD)/firmware{0,1}.bin to the board via ST-LINK using OpenOCD" + $(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(TEXT0_ADDR) $(BUILD)/firmware1.bin $(TEXT1_ADDR)" + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf + $(ECHO) "GEN $@" $(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $(BUILD)/firmware0.bin $(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $(BUILD)/firmware1.bin - $(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware0.bin -b $(TEXT_ADDR):$(BUILD)/firmware1.bin $@ + $(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware0.bin -b $(TEXT1_ADDR):$(BUILD)/firmware1.bin $@ + +endif $(BUILD)/firmware.hex: $(BUILD)/firmware.elf - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(OBJCOPY) -O ihex $< $@ $(BUILD)/firmware.elf: $(OBJ) @@ -445,7 +553,7 @@ main.c: $(GEN_CDCINF_HEADER) # Use a pattern rule here so that make will only call make-pins.py once to make # both pins_$(BOARD).c and pins.h $(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC) $(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c @@ -460,22 +568,22 @@ CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h modmachine.c: $(GEN_PLLFREQTABLE_HDR) $(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD) - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(PYTHON) $(PLLVALUES) -c file:boards/$(BOARD)/stm32$(MCU_SERIES)xx_hal_conf.h > $@ $(BUILD)/modstm.o: $(GEN_STMCONST_HDR) # Use a pattern rule here so that make will only call make-stmconst.py once to # make both modstm_const.h and modstm_qstr.h $(HEADER_BUILD)/%_const.h $(BUILD)/%_qstr.h: $(CMSIS_MCU_HDR) make-stmconst.py | $(HEADER_BUILD) - $(ECHO) "Create stmconst $@" + $(ECHO) "GEN stmconst $@" $(Q)$(PYTHON) make-stmconst.py --qstr $(GEN_STMCONST_QSTR) --mpz $(GEN_STMCONST_MPZ) $(CMSIS_MCU_HDR) > $(GEN_STMCONST_HDR) $(GEN_CDCINF_HEADER): $(GEN_CDCINF_FILE) $(FILE2H) | $(HEADER_BUILD) - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(PYTHON) $(FILE2H) $< > $@ $(GEN_CDCINF_FILE): $(CDCINF_TEMPLATE) $(INSERT_USB_IDS) $(USB_IDS_FILE) | $(HEADER_BUILD) - $(ECHO) "Create $@" + $(ECHO) "GEN $@" $(Q)$(PYTHON) $(INSERT_USB_IDS) $(USB_IDS_FILE) $< > $@ include $(TOP)/py/mkrules.mk diff --git a/ports/stm32/README.md b/ports/stm32/README.md index bb184e8db6..a0c3b7ff39 100644 --- a/ports/stm32/README.md +++ b/ports/stm32/README.md @@ -1,9 +1,9 @@ MicroPython port to STM32 MCUs ============================== -This directory contains the port of MicroPython to ST's line of STM32Fxxx -microcontrollers. It is based on the STM32Cube HAL library and currently -supports: STM32F401, STM32F405, STM32F411, STM32F429, STM32F746. +This directory contains the port of MicroPython to ST's line of STM32 +microcontrollers. Supported MCU series are: STM32F0, STM32F4, STM32F7 and +STM32L4. Parts of the code here utilise the STM32Cube HAL library. The officially supported boards are the line of pyboards: PYBv1.0 and PYBv1.1 (both with STM32F405), and PYBLITEv1.0 (with STM32F411). See @@ -14,6 +14,12 @@ Other boards that are supported include ST Discovery and Nucleo boards. See the boards/ subdirectory, which contains the configuration files used to build each individual board. +The STM32H7 series has preliminary support: there is a working REPL via +USB and UART, as well as very basic peripheral support, but some things do +not work and none of the advanced features of the STM32H7 are yet supported, +such as the clock tree. At this point the STM32H7 should be considered as a +fast version of the STM32F7. + Build instructions ------------------ diff --git a/ports/stm32/accel.c b/ports/stm32/accel.c index 7b36e20823..49674eb2da 100644 --- a/ports/stm32/accel.c +++ b/ports/stm32/accel.c @@ -30,7 +30,6 @@ #include "py/mphal.h" #include "py/runtime.h" #include "pin.h" -#include "genhdr/pins.h" #include "i2c.h" #include "accel.h" @@ -47,7 +46,7 @@ /// /// Raw values are between -32 and 31. -#define MMA_ADDR (0x98) +#define MMA_ADDR (76) #define MMA_REG_X (0) #define MMA_REG_Y (1) #define MMA_REG_Z (2) @@ -57,44 +56,35 @@ void accel_init(void) { // PB5 is connected to AVDD; pull high to enable MMA accel device - mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD - mp_hal_pin_output(&MICROPY_HW_MMA_AVDD_PIN); + mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD + mp_hal_pin_output(MICROPY_HW_MMA_AVDD_PIN); } STATIC void accel_start(void) { // start the I2C bus in master mode - I2CHandle1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; - I2CHandle1.Init.ClockSpeed = 400000; - I2CHandle1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; - I2CHandle1.Init.DutyCycle = I2C_DUTYCYCLE_16_9; - I2CHandle1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; - I2CHandle1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; - I2CHandle1.Init.OwnAddress1 = PYB_I2C_MASTER_ADDRESS; - I2CHandle1.Init.OwnAddress2 = 0xfe; // unused - i2c_init(&I2CHandle1); + i2c_init(I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA, 400000); // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again - mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off + mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off mp_hal_delay_ms(30); - mp_hal_pin_high(&MICROPY_HW_MMA_AVDD_PIN); // turn on + mp_hal_pin_high(MICROPY_HW_MMA_AVDD_PIN); // turn on mp_hal_delay_ms(30); - HAL_StatusTypeDef status; - - for (int i = 0; i < 10; i++) { - status = HAL_I2C_IsDeviceReady(&I2CHandle1, MMA_ADDR, 10, 200); - if (status == HAL_OK) { + int ret; + for (int i = 0; i < 4; i++) { + ret = i2c_writeto(I2C1, MMA_ADDR, NULL, 0, true); + if (ret == 0) { break; } } - if (status != HAL_OK) { + if (ret != 0) { mp_raise_msg(&mp_type_OSError, "accelerometer not found"); } // set MMA to active mode - uint8_t data[1] = {1}; // active mode - status = HAL_I2C_Mem_Write(&I2CHandle1, MMA_ADDR, MMA_REG_MODE, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[2] = {MMA_REG_MODE, 1}; // active mode + i2c_writeto(I2C1, MMA_ADDR, data, 2, true); // wait for MMA to become active mp_hal_delay_ms(30); @@ -136,8 +126,9 @@ STATIC mp_obj_t pyb_accel_make_new(const mp_obj_type_t *type, size_t n_args, siz } STATIC mp_obj_t read_axis(int axis) { - uint8_t data[1]; - HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, axis, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[1] = { axis }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_readfrom(I2C1, MMA_ADDR, data, 1, true); return mp_obj_new_int(MMA_AXIS_SIGNED_VALUE(data[0])); } @@ -165,8 +156,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_z_obj, pyb_accel_z); /// \method tilt() /// Get the tilt register. STATIC mp_obj_t pyb_accel_tilt(mp_obj_t self_in) { - uint8_t data[1]; - HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, MMA_REG_TILT, I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[1] = { MMA_REG_TILT }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_readfrom(I2C1, MMA_ADDR, data, 1, true); return mp_obj_new_int(data[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_tilt_obj, pyb_accel_tilt); @@ -178,8 +170,9 @@ STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) { memmove(self->buf, self->buf + NUM_AXIS, NUM_AXIS * (FILT_DEPTH - 1) * sizeof(int16_t)); - uint8_t data[NUM_AXIS]; - HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, MMA_REG_X, I2C_MEMADD_SIZE_8BIT, data, NUM_AXIS, 200); + uint8_t data[NUM_AXIS] = { MMA_REG_X }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_readfrom(I2C1, MMA_ADDR, data, 3, true); mp_obj_t tuple[NUM_AXIS]; for (int i = 0; i < NUM_AXIS; i++) { @@ -196,16 +189,16 @@ STATIC mp_obj_t pyb_accel_filtered_xyz(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_accel_filtered_xyz_obj, pyb_accel_filtered_xyz); STATIC mp_obj_t pyb_accel_read(mp_obj_t self_in, mp_obj_t reg) { - uint8_t data[1]; - HAL_I2C_Mem_Read(&I2CHandle1, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[1] = { mp_obj_get_int(reg) }; + i2c_writeto(I2C1, MMA_ADDR, data, 1, false); + i2c_writeto(I2C1, MMA_ADDR, data, 1, true); return mp_obj_new_int(data[0]); } MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_read_obj, pyb_accel_read); STATIC mp_obj_t pyb_accel_write(mp_obj_t self_in, mp_obj_t reg, mp_obj_t val) { - uint8_t data[1]; - data[0] = mp_obj_get_int(val); - HAL_I2C_Mem_Write(&I2CHandle1, MMA_ADDR, mp_obj_get_int(reg), I2C_MEMADD_SIZE_8BIT, data, 1, 200); + uint8_t data[2] = { mp_obj_get_int(reg), mp_obj_get_int(val) }; + i2c_writeto(I2C1, MMA_ADDR, data, 2, true); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(pyb_accel_write_obj, pyb_accel_write); diff --git a/ports/stm32/accel.h b/ports/stm32/accel.h index fc35f77756..1fea1249c7 100644 --- a/ports/stm32/accel.h +++ b/ports/stm32/accel.h @@ -23,11 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_ACCEL_H -#define MICROPY_INCLUDED_STMHAL_ACCEL_H +#ifndef MICROPY_INCLUDED_STM32_ACCEL_H +#define MICROPY_INCLUDED_STM32_ACCEL_H extern const mp_obj_type_t pyb_accel_type; void accel_init(void); -#endif // MICROPY_INCLUDED_STMHAL_ACCEL_H +#endif // MICROPY_INCLUDED_STM32_ACCEL_H diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 9a0dc56a37..f439503e61 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -32,9 +32,10 @@ #include "py/mphal.h" #include "adc.h" #include "pin.h" -#include "genhdr/pins.h" #include "timer.h" +#if MICROPY_HW_ENABLE_ADC + /// \moduleref pyb /// \class ADC - analog to digital conversion: read analog values on a pin /// @@ -50,11 +51,23 @@ /// val = adc.read_core_vref() # read MCU VREF /* ADC defintions */ +#if defined(STM32H7) +#define ADCx (ADC3) +#else #define ADCx (ADC1) -#define ADCx_CLK_ENABLE __ADC1_CLK_ENABLE +#endif +#define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE #define ADC_NUM_CHANNELS (19) -#if defined(MCU_SERIES_F4) +#if defined(STM32F0) + +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (15) +#define ADC_CAL_ADDRESS (0x1ffff7ba) +#define ADC_CAL1 ((uint16_t*)0x1ffff7b8) +#define ADC_CAL2 ((uint16_t*)0x1ffff7c2) + +#elif defined(STM32F4) #define ADC_FIRST_GPIO_CHANNEL (0) #define ADC_LAST_GPIO_CHANNEL (15) @@ -62,15 +75,30 @@ #define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2)) #define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4)) -#elif defined(MCU_SERIES_F7) +#elif defined(STM32F7) #define ADC_FIRST_GPIO_CHANNEL (0) #define ADC_LAST_GPIO_CHANNEL (15) +#if defined(STM32F722xx) || defined(STM32F723xx) || \ + defined(STM32F732xx) || defined(STM32F733xx) +#define ADC_CAL_ADDRESS (0x1ff07a2a) +#else #define ADC_CAL_ADDRESS (0x1ff0f44a) +#endif + #define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2)) #define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4)) -#elif defined(MCU_SERIES_L4) +#elif defined(STM32H7) + +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (16) +#define ADC_CAL_ADDRESS (0x1FF1E860) +#define ADC_CAL1 ((uint16_t*)(0x1FF1E820)) +#define ADC_CAL2 ((uint16_t*)(0x1FF1E840)) +#define ADC_CHANNEL_VBAT ADC_CHANNEL_VBAT_DIV4 + +#elif defined(STM32L4) #define ADC_FIRST_GPIO_CHANNEL (1) #define ADC_LAST_GPIO_CHANNEL (16) @@ -84,22 +112,32 @@ #endif -#if defined(STM32F405xx) || defined(STM32F415xx) || \ +#if defined(STM32F091xC) +#define VBAT_DIV (2) +#elif defined(STM32F405xx) || defined(STM32F415xx) || \ defined(STM32F407xx) || defined(STM32F417xx) || \ defined(STM32F401xC) || defined(STM32F401xE) || \ defined(STM32F411xE) #define VBAT_DIV (2) #elif defined(STM32F427xx) || defined(STM32F429xx) || \ defined(STM32F437xx) || defined(STM32F439xx) || \ + defined(STM32F722xx) || defined(STM32F723xx) || \ + defined(STM32F732xx) || defined(STM32F733xx) || \ defined(STM32F746xx) || defined(STM32F767xx) || \ defined(STM32F769xx) || defined(STM32F446xx) #define VBAT_DIV (4) -#elif defined(STM32L475xx) || defined(STM32L476xx) +#elif defined(STM32H743xx) +#define VBAT_DIV (4) +#elif defined(STM32L475xx) || defined(STM32L476xx) || \ + defined(STM32L496xx) #define VBAT_DIV (3) #else #error Unsupported processor #endif +// Timeout for waiting for end-of-conversion, in ms +#define EOC_TIMEOUT (10) + /* Core temperature sensor definitions */ #define CORE_TEMP_V25 (943) /* (0.76v/3.3v)*(2^ADC resoultion) */ #define CORE_TEMP_AVG_SLOPE (3) /* (2.5mv/3.3v)*(2^ADC resoultion) */ @@ -117,7 +155,7 @@ typedef struct _pyb_obj_adc_t { // convert user-facing channel number into internal channel number static inline uint32_t adc_get_internal_channel(uint32_t channel) { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) // on F4 and F7 MCUs we want channel 16 to always be the TEMPSENSOR // (on some MCUs ADC_CHANNEL_TEMPSENSOR=16, on others it doesn't) if (channel == 16) { @@ -128,9 +166,12 @@ static inline uint32_t adc_get_internal_channel(uint32_t channel) { } STATIC bool is_adcx_channel(int channel) { -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F411xE) + // The HAL has an incorrect IS_ADC_CHANNEL macro for the F411 so we check for temp + return IS_ADC_CHANNEL(channel) || channel == ADC_CHANNEL_TEMPSENSOR; +#elif defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) return IS_ADC_CHANNEL(channel); -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) ADC_HandleTypeDef handle; handle.Instance = ADCx; return IS_ADC_CHANNEL(&handle, channel); @@ -141,9 +182,9 @@ STATIC bool is_adcx_channel(int channel) { STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { uint32_t tickstart = HAL_GetTick(); -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) { -#elif defined(MCU_SERIES_L4) +#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) { #else #error Unsupported processor @@ -155,74 +196,82 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { } STATIC void adcx_clock_enable(void) { -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) ADCx_CLK_ENABLE(); -#elif defined(MCU_SERIES_L4) +#elif defined(STM32H7) + __HAL_RCC_ADC3_CLK_ENABLE(); + __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP); +#elif defined(STM32L4) __HAL_RCC_ADC_CLK_ENABLE(); #else #error Unsupported processor #endif } +STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { + adcx_clock_enable(); + + adch->Instance = ADCx; + adch->Init.Resolution = resolution; + adch->Init.ContinuousConvMode = DISABLE; + adch->Init.DiscontinuousConvMode = DISABLE; + #if !defined(STM32F0) + adch->Init.NbrOfDiscConversion = 0; + adch->Init.NbrOfConversion = 1; + #endif + adch->Init.EOCSelection = ADC_EOC_SINGLE_CONV; + adch->Init.ExternalTrigConv = ADC_SOFTWARE_START; + adch->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) + adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; + adch->Init.ScanConvMode = DISABLE; + adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adch->Init.DMAContinuousRequests = DISABLE; + #elif defined(STM32H7) + adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; + adch->Init.BoostMode = ENABLE; + adch->Init.ScanConvMode = DISABLE; + adch->Init.LowPowerAutoWait = DISABLE; + adch->Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; + adch->Init.OversamplingMode = DISABLE; + adch->Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE; + adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; + #elif defined(STM32L4) + adch->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; + adch->Init.ScanConvMode = ADC_SCAN_DISABLE; + adch->Init.LowPowerAutoWait = DISABLE; + adch->Init.Overrun = ADC_OVR_DATA_PRESERVED; + adch->Init.OversamplingMode = DISABLE; + adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adch->Init.DMAContinuousRequests = DISABLE; + #else + #error Unsupported processor + #endif + + HAL_ADC_Init(adch); + + #if defined(STM32H7) + HAL_ADCEx_Calibration_Start(adch, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); + #endif +} + STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { if (!is_adcx_channel(adc_obj->channel)) { return; } if (ADC_FIRST_GPIO_CHANNEL <= adc_obj->channel && adc_obj->channel <= ADC_LAST_GPIO_CHANNEL) { - // Channels 0-16 correspond to real pins. Configure the GPIO pin in - // ADC mode. - const pin_obj_t *pin = pin_adc1[adc_obj->channel]; - mp_hal_gpio_clock_enable(pin->gpio); - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Pin = pin->pin_mask; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) - GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; -#elif defined(MCU_SERIES_L4) - GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; -#else - #error Unsupported processor -#endif - GPIO_InitStructure.Pull = GPIO_NOPULL; - HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure); + // Channels 0-16 correspond to real pins. Configure the GPIO pin in ADC mode. + const pin_obj_t *pin = pin_adc1[adc_obj->channel]; + mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); } - adcx_clock_enable(); + adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B); - ADC_HandleTypeDef *adcHandle = &adc_obj->handle; - adcHandle->Instance = ADCx; - adcHandle->Init.ContinuousConvMode = DISABLE; - adcHandle->Init.DiscontinuousConvMode = DISABLE; - adcHandle->Init.NbrOfDiscConversion = 0; - adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; - adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT; - adcHandle->Init.NbrOfConversion = 1; - adcHandle->Init.DMAContinuousRequests = DISABLE; - adcHandle->Init.Resolution = ADC_RESOLUTION_12B; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) - adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; - adcHandle->Init.ScanConvMode = DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; - adcHandle->Init.EOCSelection = DISABLE; -#elif defined(MCU_SERIES_L4) - adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; - adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; - adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV; - adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START; - adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; - adcHandle->Init.LowPowerAutoWait = DISABLE; - adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED; - adcHandle->Init.OversamplingMode = DISABLE; -#else - #error Unsupported processor -#endif - - HAL_ADC_Init(adcHandle); - -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) ADC_MultiModeTypeDef multimode; multimode.Mode = ADC_MODE_INDEPENDENT; - if (HAL_ADCEx_MultiModeConfigChannel(adcHandle, &multimode) != HAL_OK) + if (HAL_ADCEx_MultiModeConfigChannel(&adc_obj->handle, &multimode) != HAL_OK) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Can not set multimode on ADC1 channel: %d", adc_obj->channel)); } @@ -234,31 +283,39 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.Channel = channel; sConfig.Rank = 1; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F0) + sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5; +#elif defined(STM32F4) || defined(STM32F7) sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32H7) + sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5; + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.OffsetRightShift = DISABLE; + sConfig.OffsetSignedSaturation = DISABLE; +#elif defined(STM32L4) sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.Offset = 0; #else #error Unsupported processor #endif - sConfig.Offset = 0; HAL_ADC_ConfigChannel(adc_handle, &sConfig); } STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) { - uint32_t rawValue = 0; - HAL_ADC_Start(adcHandle); - if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK - && (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_EOC_REG) == HAL_ADC_STATE_EOC_REG) { - rawValue = HAL_ADC_GetValue(adcHandle); - } + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); + uint32_t value = ADCx->DR; HAL_ADC_Stop(adcHandle); + return value; +} - return rawValue; +STATIC uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) { + adc_config_channel(adcHandle, channel); + return adc_read_channel(adcHandle); } /******************************************************************************/ @@ -268,7 +325,7 @@ STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t pyb_obj_adc_t *self = self_in; mp_print_str(print, "pin_name, PRINT_STR); - mp_printf(print, " channel=%lu>", self->channel); + mp_printf(print, " channel=%u>", self->channel); } /// \classmethod \constructor(pin) @@ -322,10 +379,7 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ /// will be between 0 and 4095. STATIC mp_obj_t adc_read(mp_obj_t self_in) { pyb_obj_adc_t *self = self_in; - - adc_config_channel(&self->handle, self->channel); - uint32_t data = adc_read_channel(&self->handle); - return mp_obj_new_int(data); + return mp_obj_new_int(adc_config_and_read_channel(&self->handle, self->channel)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); @@ -401,9 +455,9 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ HAL_ADC_Start(&self->handle); } else { // for subsequent samples we can just set the "start sample" bit -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) SET_BIT(ADCx->CR, ADC_CR_ADSTART); #else #error Unsupported processor @@ -411,8 +465,7 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ } // wait for sample to complete - #define READ_TIMED_TIMEOUT (10) // in ms - adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT); + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); // read value uint value = ADCx->DR; @@ -438,9 +491,114 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ } STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed); +// read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer) +// +// Read analog values from multiple ADC's into buffers at a rate set by the +// timer. The ADC values have 12-bit resolution and are stored directly into +// the corresponding buffer if its element size is 16 bits or greater, otherwise +// the sample resolution will be reduced to 8 bits. +// +// This function should not allocate any heap memory. +STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_in, mp_obj_t tim_in) { + size_t nadcs, nbufs; + mp_obj_t *adc_array, *buf_array; + mp_obj_get_array(adc_array_in, &nadcs, &adc_array); + mp_obj_get_array(buf_array_in, &nbufs, &buf_array); + + if (nadcs < 1) { + mp_raise_ValueError("need at least 1 ADC"); + } + if (nadcs != nbufs) { + mp_raise_ValueError("length of ADC and buffer lists differ"); + } + + // Get buf for first ADC, get word size, check other buffers match in type + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_array[0], &bufinfo, MP_BUFFER_WRITE); + size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL); + void *bufptrs[nbufs]; + for (uint array_index = 0; array_index < nbufs; array_index++) { + mp_buffer_info_t bufinfo_curr; + mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); + if ((bufinfo.len != bufinfo_curr.len) || (bufinfo.typecode != bufinfo_curr.typecode)) { + mp_raise_ValueError("size and type of buffers must match"); + } + bufptrs[array_index] = bufinfo_curr.buf; + } + + // Use the supplied timer object as the sampling time base + TIM_HandleTypeDef *tim; + tim = pyb_timer_get_handle(tim_in); + + // Start adc; this is slow so wait for it to start + pyb_obj_adc_t *adc0 = adc_array[0]; + adc_config_channel(&adc0->handle, adc0->channel); + HAL_ADC_Start(&adc0->handle); + // Wait for sample to complete and discard + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); + // Read (and discard) value + uint value = ADCx->DR; + + // Ensure first sample is on a timer tick + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { + } + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + + // Overrun check: assume success + bool success = true; + size_t nelems = bufinfo.len / typesize; + for (size_t elem_index = 0; elem_index < nelems; elem_index++) { + if (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) != RESET) { + // Timer has already triggered + success = false; + } else { + // Wait for the timer to trigger so we sample at the correct frequency + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { + } + } + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + + for (size_t array_index = 0; array_index < nadcs; array_index++) { + pyb_obj_adc_t *adc = adc_array[array_index]; + // configure the ADC channel + adc_config_channel(&adc->handle, adc->channel); + // for the first sample we need to turn the ADC on + // ADC is started: set the "start sample" bit + #if defined(STM32F4) || defined(STM32F7) + ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; + #elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) + SET_BIT(ADCx->CR, ADC_CR_ADSTART); + #else + #error Unsupported processor + #endif + // wait for sample to complete + adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); + + // read value + value = ADCx->DR; + + // store values in buffer + if (typesize == 1) { + value >>= 4; + } + mp_binary_set_val_array_from_int(bufinfo.typecode, bufptrs[array_index], elem_index, value); + } + } + + // Turn the ADC off + adc0 = adc_array[0]; + HAL_ADC_Stop(&adc0->handle); + + return mp_obj_new_bool(success); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_multi_fun_obj, adc_read_timed_multi); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(adc_read_timed_multi_obj, MP_ROM_PTR(&adc_read_timed_multi_fun_obj)); + STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&adc_read_obj) }, { MP_ROM_QSTR(MP_QSTR_read_timed), MP_ROM_PTR(&adc_read_timed_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_timed_multi), MP_ROM_PTR(&adc_read_timed_multi_obj) }, }; STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table); @@ -464,7 +622,9 @@ typedef struct _pyb_adc_all_obj_t { void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_mask) { switch (resolution) { + #if !defined(STM32H7) case 6: resolution = ADC_RESOLUTION_6B; break; + #endif case 8: resolution = ADC_RESOLUTION_8B; break; case 10: resolution = ADC_RESOLUTION_10B; break; case 12: resolution = ADC_RESOLUTION_12B; break; @@ -480,57 +640,21 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m // ADC mode. const pin_obj_t *pin = pin_adc1[channel]; if (pin) { - mp_hal_gpio_clock_enable(pin->gpio); - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Pin = pin->pin_mask; - GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; - GPIO_InitStructure.Pull = GPIO_NOPULL; - HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure); + mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); } } } - adcx_clock_enable(); - - ADC_HandleTypeDef *adcHandle = &adc_all->handle; - adcHandle->Instance = ADCx; - adcHandle->Init.Resolution = resolution; - adcHandle->Init.ContinuousConvMode = DISABLE; - adcHandle->Init.DiscontinuousConvMode = DISABLE; - adcHandle->Init.NbrOfDiscConversion = 0; - adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; - adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT; - adcHandle->Init.NbrOfConversion = 1; - adcHandle->Init.DMAContinuousRequests = DISABLE; - adcHandle->Init.EOCSelection = DISABLE; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) - adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; - adcHandle->Init.ScanConvMode = DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; -#elif defined(MCU_SERIES_L4) - adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; - adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1; - adcHandle->Init.LowPowerAutoWait = DISABLE; - adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED; - adcHandle->Init.OversamplingMode = DISABLE; -#else - #error Unsupported processor -#endif - - HAL_ADC_Init(adcHandle); -} - -uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) { - adc_config_channel(adcHandle, channel); - return adc_read_channel(adcHandle); + adcx_init_periph(&adc_all->handle, resolution); } int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { - uint32_t res_reg = __HAL_ADC_GET_RESOLUTION(adcHandle); + uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle); switch (res_reg) { + #if !defined(STM32H7) case ADC_RESOLUTION_6B: return 6; + #endif case ADC_RESOLUTION_8B: return 8; case ADC_RESOLUTION_10B: return 10; } @@ -568,7 +692,7 @@ float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) { // be 12-bits. raw_value <<= (12 - adc_get_resolution(adcHandle)); - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) // ST docs say that (at least on STM32F42x and STM32F43x), VBATE must // be disabled when TSVREFE is enabled for TEMPSENSOR and VREFINT // conversions to work. VBATE is enabled by the above call to read @@ -675,3 +799,5 @@ const mp_obj_type_t pyb_adc_all_type = { .make_new = adc_all_make_new, .locals_dict = (mp_obj_dict_t*)&adc_all_locals_dict, }; + +#endif // MICROPY_HW_ENABLE_ADC diff --git a/ports/stm32/adc.h b/ports/stm32/adc.h index c90e6b3433..4ae6022bc3 100644 --- a/ports/stm32/adc.h +++ b/ports/stm32/adc.h @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_ADC_H -#define MICROPY_INCLUDED_STMHAL_ADC_H +#ifndef MICROPY_INCLUDED_STM32_ADC_H +#define MICROPY_INCLUDED_STM32_ADC_H extern const mp_obj_type_t pyb_adc_type; extern const mp_obj_type_t pyb_adc_all_type; -#endif // MICROPY_INCLUDED_STMHAL_ADC_H +#endif // MICROPY_INCLUDED_STM32_ADC_H diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h index 77f029c006..3ab3d5fa17 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h +++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.h @@ -2,17 +2,9 @@ #define MICROPY_HW_MCU_NAME "STM32L475" #define MICROPY_HW_HAS_SWITCH (1) -#define MICROPY_HW_HAS_FLASH (0) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) +#define MICROPY_HW_ENABLE_USB (1) // MSI is used and is 4MHz #define MICROPY_HW_CLK_PLLM (1) @@ -74,3 +66,6 @@ #define MICROPY_HW_LED2 (pin_B14) // green #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk index 1ba61a3274..55e443e919 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk +++ b/ports/stm32/boards/B_L475E_IOT01A/mpconfigboard.mk @@ -3,6 +3,7 @@ CMSIS_MCU = STM32L475xx # The stm32l475 does not have a LDC controller which is # the only diffrence to the stm32l476 - so reuse some files. AF_FILE = boards/stm32l476_af.csv -LD_FILE = boards/stm32l476xg.ld -TEXT_ADDR = 0x08004000 +LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h b/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h index 9348e06790..6bfb28118a 100644 --- a/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/B_L475E_IOT01A/stm32l4xx_hal_conf.h @@ -45,7 +45,6 @@ extern "C" { #endif -#define USE_USB_FS /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ diff --git a/ports/stm32/boards/CERB40/mpconfigboard.h b/ports/stm32/boards/CERB40/mpconfigboard.h index 284de7a40f..7c166922be 100644 --- a/ports/stm32/boards/CERB40/mpconfigboard.h +++ b/ports/stm32/boards/CERB40/mpconfigboard.h @@ -1,20 +1,11 @@ -#define CERB40 - #define MICROPY_HW_BOARD_NAME "Cerb40" #define MICROPY_HW_MCU_NAME "STM32F405RG" -#define MICROPY_HW_HAS_SWITCH (0) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) @@ -58,10 +49,17 @@ #define MICROPY_HW_SPI3_MISO (pin_B4) #define MICROPY_HW_SPI3_MOSI (pin_B5) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // The Cerb40 has No LEDs // The Cerb40 has No SDCard // USB config +#define MICROPY_HW_USB_FS (1) //#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) //#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/CERB40/mpconfigboard.mk b/ports/stm32/boards/CERB40/mpconfigboard.mk index 5734c66904..40972b3850 100644 --- a/ports/stm32/boards/CERB40/mpconfigboard.mk +++ b/ports/stm32/boards/CERB40/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/CERB40/pins.csv b/ports/stm32/boards/CERB40/pins.csv index 411031e8f5..cca0bc0536 100644 --- a/ports/stm32/boards/CERB40/pins.csv +++ b/ports/stm32/boards/CERB40/pins.csv @@ -44,3 +44,7 @@ UART3_TX,PD8 UART3_RX,PD9 UART3_RTS,PD12 UART3_CTS,PD11 +CAN2_TX,PB13 +CAN2_RX,PB12 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h index d6aca705cf..e71ba33697 100644 --- a/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h index d065180d8a..53c7f3cd50 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h +++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.h @@ -9,16 +9,9 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) -#define MICROPY_HW_ENABLE_RNG (0) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) // Pico has an 8 MHz HSE and the F401 does 84 MHz max #define MICROPY_HW_CLK_PLLM (5) @@ -70,3 +63,6 @@ #define MICROPY_HW_LED4 (pin_B12) // green #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk index d531a594a1..16cacc089e 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk +++ b/ports/stm32/boards/ESPRUINO_PICO/mpconfigboard.mk @@ -1,7 +1,9 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F401xE AF_FILE = boards/stm32f401_af.csv -LD_FILE = boards/stm32f401xd.ld +LD_FILES = boards/stm32f401xd.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 # Don't include default frozen modules because MCU is tight on flash space FROZEN_MPY_DIR ?= diff --git a/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h index 11a396b73e..d27e2e9ef0 100644 --- a/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/ESPRUINO_PICO/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.h b/ports/stm32/boards/HYDRABUS/mpconfigboard.h index 38fba9787a..2e73d3ec88 100644 --- a/ports/stm32/boards/HYDRABUS/mpconfigboard.h +++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.h @@ -1,20 +1,12 @@ -#define HYDRABUSV10 - #define MICROPY_HW_BOARD_NAME "HydraBus1.0" #define MICROPY_HW_MCU_NAME "STM32F4" #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) -#define MICROPY_HW_ENABLE_RTC (0) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (0) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -78,4 +70,5 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (1) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/HYDRABUS/mpconfigboard.mk b/ports/stm32/boards/HYDRABUS/mpconfigboard.mk index 5734c66904..40972b3850 100644 --- a/ports/stm32/boards/HYDRABUS/mpconfigboard.mk +++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h index d3df51c101..daf9b63cec 100644 --- a/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/HYDRABUS/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/LIMIFROG/board_init.c b/ports/stm32/boards/LIMIFROG/board_init.c index 72f9208424..67ccf23cc5 100644 --- a/ports/stm32/boards/LIMIFROG/board_init.c +++ b/ports/stm32/boards/LIMIFROG/board_init.c @@ -104,10 +104,10 @@ static void LBF_DFU_If_Needed(void) // Initialize and assert pin BTLE_RST // (hw reset to BLE module, so it won't drive UART3) - __GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Pin = BT_RST_PIN; HAL_GPIO_Init(BT_RST_PORT, &GPIO_InitStruct); @@ -124,7 +124,7 @@ static void LBF_DFU_If_Needed(void) // Initialize Extension Port Position 10 = PB8 (bears I2C1_SCL) // Use weak pull-up to detect if pin is externally pulled low - __GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Pin = CONN_POS10_PIN; diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.h b/ports/stm32/boards/LIMIFROG/mpconfigboard.h index 42b862fcf5..d27c2e66ef 100644 --- a/ports/stm32/boards/LIMIFROG/mpconfigboard.h +++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.h @@ -3,16 +3,9 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_BOARD_EARLY_INIT LIMIFROG_board_early_init void LIMIFROG_board_early_init(void); @@ -58,4 +51,5 @@ void LIMIFROG_board_early_init(void); #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_FS (1) // #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk index a1304b6559..2adc98f0b1 100644 --- a/ports/stm32/boards/LIMIFROG/mpconfigboard.mk +++ b/ports/stm32/boards/LIMIFROG/mpconfigboard.mk @@ -1,5 +1,6 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv -LD_FILE = boards/stm32l476xe.ld -TEXT_ADDR = 0x08004000 +LD_FILES = boards/stm32l476xe.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 diff --git a/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h index 9348e06790..6bfb28118a 100644 --- a/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/LIMIFROG/stm32l4xx_hal_conf.h @@ -45,7 +45,6 @@ extern "C" { #endif -#define USE_USB_FS /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c index 085034b2d8..53df72503b 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c +++ b/ports/stm32/boards/NETDUINO_PLUS_2/board_init.c @@ -2,11 +2,11 @@ void NETDUINO_PLUS_2_board_early_init(void) { - __GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); // Turn off the backlight. LCD_BL_CTRL = PK3 GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h index 9586ae4e55..3125767562 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -8,15 +8,9 @@ // SPI, so the driver needs to be converted to support that before // we can turn this on. #define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) -#define MICROPY_HW_ENABLE_RTC (0) -#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) void NETDUINO_PLUS_2_board_early_init(void); #define MICROPY_BOARD_EARLY_INIT NETDUINO_PLUS_2_board_early_init @@ -69,5 +63,6 @@ void NETDUINO_PLUS_2_board_early_init(void); #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) -// USB VBUS detect pin +// USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk index 5734c66904..40972b3850 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk +++ b/ports/stm32/boards/NETDUINO_PLUS_2/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv b/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv index 3e71fade6e..53ffa9d1fe 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv +++ b/ports/stm32/boards/NETDUINO_PLUS_2/pins.csv @@ -33,3 +33,5 @@ UART3_RX,PD9 UART3_RTS,PD12 UART3_CTS,PD11 UART5_TX,PC12 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h index 42c2c4e9be..4cb5a83e45 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h new file mode 100644 index 0000000000..3546d521bf --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.h @@ -0,0 +1,59 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO-F091RC" +#define MICROPY_HW_MCU_NAME "STM32F091RCT6" + +#define MICROPY_EMIT_THUMB (0) +#define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_PY_USOCKET (0) +#define MICROPY_PY_NETWORK (0) +#define MICROPY_PY_STM (0) +#define MICROPY_PY_PYB_LEGACY (0) +#define MICROPY_VFS_FAT (0) + +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_ADC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_HAS_SWITCH (1) + +// For system clock, board uses internal 48MHz, HSI48 + +// The board has an external 32kHz crystal +#define MICROPY_HW_RTC_USE_LSE (1) + +// UART config +#define MICROPY_HW_UART1_TX (pin_B6) +#define MICROPY_HW_UART1_RX (pin_B7) +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_A3) + +// USART2 is connected to the ST-LINK USB VCP +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) // Arduino D15, pin 3 on CN10 +#define MICROPY_HW_I2C1_SDA (pin_B9) // Arduino D14, pin 5 on CN10 +#define MICROPY_HW_I2C2_SCL (pin_B10) // Arduino D6, pin 25 on CN10 +#define MICROPY_HW_I2C2_SDA (pin_B11) // pin 18 on CN10 + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A15) // pin 17 on CN7 +#define MICROPY_HW_SPI1_SCK (pin_A5) // Arduino D13, pin 11 on CN10 +#define MICROPY_HW_SPI1_MISO (pin_A6) // Arduino D12, pin 13 on CN10 +#define MICROPY_HW_SPI1_MOSI (pin_A7) // Arduino D11, pin 15 on CN10 +#define MICROPY_HW_SPI2_NSS (pin_B12) // pin 16 on CN10 +#define MICROPY_HW_SPI2_SCK (pin_B13) // pin 30 on CN10 +#define MICROPY_HW_SPI2_MISO (pin_B14) // pin 28 on CN10 +#define MICROPY_HW_SPI2_MOSI (pin_B15) // pin 26 on CN10 + +// USER B1 has a pull-up and is active low +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (0) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) +#define MICROPY_HW_USRSW_PRESSED (0) + +// NUCLEO-64 has one user LED +#define MICROPY_HW_LED1 (pin_A5) // green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk new file mode 100644 index 0000000000..1d66f7e6b6 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F091RC/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = f0 +CMSIS_MCU = STM32F091xC +AF_FILE = boards/stm32f091_af.csv +LD_FILES = boards/stm32f091xc.ld boards/common_basic.ld + +# Don't include default frozen modules because MCU is tight on flash space +FROZEN_MPY_DIR ?= diff --git a/ports/stm32/boards/NUCLEO_F091RC/pins.csv b/ports/stm32/boards/NUCLEO_F091RC/pins.csv new file mode 100644 index 0000000000..36d3141083 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F091RC/pins.csv @@ -0,0 +1,87 @@ +D0,PA3 +D1,PA2 +D2,PA10 +D3,PB3 +D4,PB5 +D5,PB4 +D6,PB10 +D7,PA8 +D8,PA9 +D9,PC7 +D10,PB6 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +A0,PA0 +A1,PA1 +A2,PA4 +A3,PB0 +A4,PC1 +A5,PC0 +RX,PA3 +TX,PA2 +SCL,PB8 +SDA,PB9 +SCK,PA5 +MISO,PA6 +MOSI,PA7 +CS,PB6 +BOOT0,PF11 +SWDIO,PA13 +SWCLK,PA14 +USER_B1,PC13 +LED_GREEN,PA5 +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD2,PD2 +PF0,PF0 +PF1,PF1 +PF11,PF11 diff --git a/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h new file mode 100644 index 0000000000..53ea047cbd --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F091RC/stm32f0xx_hal_conf.h @@ -0,0 +1,312 @@ +/** + ****************************************************************************** + * @file stm32f0xx_hal_conf_template.h + * @author MCD Application Team + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32f0xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F0xx_HAL_CONF_H +#define __STM32F0xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +#define HAL_CEC_MODULE_ENABLED +#define HAL_COMP_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +#define HAL_IRDA_MODULE_ENABLED +#define HAL_IWDG_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SMARTCARD_MODULE_ENABLED +#define HAL_SMBUS_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_TSC_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +/* ######################### Oscillator Values adaptation ################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +/** + * @brief In the following line adjust the External High Speed oscillator (HSE) Startup + * Timeout value + */ +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE 8000000U /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief In the following line adjust the Internal High Speed oscillator (HSI) Startup + * Timeout value + */ +#if !defined (HSI_STARTUP_TIMEOUT) + #define HSI_STARTUP_TIMEOUT 5000U /*!< Time out for HSI start up */ +#endif /* HSI_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator for ADC (HSI14) value. + */ +#if !defined (HSI14_VALUE) + #define HSI14_VALUE 14000000U /*!< Value of the Internal High Speed oscillator for ADC in Hz. + The real value may vary depending on the variations + in voltage and temperature. */ +#endif /* HSI14_VALUE */ + +/** + * @brief Internal High Speed oscillator for USB (HSI48) value. + */ +#if !defined (HSI48_VALUE) + #define HSI48_VALUE 48000000U /*!< Value of the Internal High Speed oscillator for USB in Hz. + The real value may vary depending on the variations + in voltage and temperature. */ +#endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE 40000U +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +/** + * @brief Time out for LSE start up value in ms. + */ +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE 3300U /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U +#define INSTRUCTION_CACHE_ENABLE 0U +#define DATA_CACHE_ENABLE 0U +#define USE_SPI_CRC 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/*#define USE_FULL_ASSERT 1*/ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f0xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f0xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f0xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f0xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f0xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f0xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f0xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32f0xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f0xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f0xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f0xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f0xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f0xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f0xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f0xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f0xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f0xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f0xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f0xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32f0xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f0xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f0xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32f0xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f0xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f0xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f0xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((char *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(char* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F0xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk index eb391bed73..4c3022f544 100644 --- a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F401xE AF_FILE = boards/stm32f401_af.csv -LD_FILE = boards/stm32f401xe.ld +LD_FILES = boards/stm32f401xe.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h index f4db4cb631..daf9b63cec 100644 --- a/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F401RE/stm32f4xx_hal_conf.h @@ -46,10 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -// This board doesn't really have USB, but the stm32 codebase doesn't build -// without some USB defined, so we leave this on for now. -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk index 71b3b19d65..df95065225 100644 --- a/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F411RE/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F411xE AF_FILE = boards/stm32f411_af.csv -LD_FILE = boards/stm32f411.ld +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h index 0c424888f8..8f0b663811 100644 --- a/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F411RE/stm32f4xx_hal_conf.h @@ -46,10 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -// This board doesn't really have USB, but the stm32 codebase doesn't build -// without some USB defined, so we leave this on for now. -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h index 42cc9d68cd..17883a1920 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -3,22 +3,15 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) -#define MICROPY_HW_CLK_PLLN (180) +#define MICROPY_HW_CLK_PLLN (336) #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) -#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_PLLQ (7) // From the reference manual, for 2.7V to 3.6V // 151-180 MHz => 5 wait states @@ -65,6 +58,12 @@ #define MICROPY_HW_SPI5_MISO (pin_F8) #define MICROPY_HW_SPI5_MOSI (pin_F9) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_C13) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) @@ -79,5 +78,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk index 1bbf808b69..d19a35c316 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F429xx AF_FILE = boards/stm32f429_af.csv -LD_FILE = boards/stm32f429.ld +LD_FILES = boards/stm32f429.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h index d121b18c5e..5b5a8a3e43 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk index e1ec6d57cf..64a80e992b 100644 --- a/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F446RE/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F446xx AF_FILE = boards/stm32f429_af.csv -LD_FILE = boards/stm32f411.ld +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h index 487ca009f2..245fb9a06a 100644 --- a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h @@ -46,10 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -// This board doesn't really have USB, but the stm32 codebase doesn't build -// without some USB defined, so we leave this on for now. -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h new file mode 100644 index 0000000000..a9fbea5766 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h @@ -0,0 +1,77 @@ +// This board is only confirmed to operate using DFU mode and openocd. +// DFU mode can be accessed by setting BOOT0 (see schematics) +// To use openocd run "OPENOCD_CONFIG=boards/openocd_stm32f7.cfg" in +// the make command. + +#define MICROPY_HW_BOARD_NAME "NUCLEO-F746ZG" +#define MICROPY_HW_MCU_NAME "STM32F746" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_USB (1) + +// HSE is 8MHz +// VCOClock = HSE * PLLN / PLLM = 8 MHz * 216 / 4 = 432 MHz +// SYSCLK = VCOClock / PLLP = 432 MHz / 2 = 216 MHz +// USB/SDMMC/RNG Clock = VCOClock / PLLQ = 432 MHz / 9 = 48 MHz +#define MICROPY_HW_CLK_PLLM (4) +#define MICROPY_HW_CLK_PLLN (216) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) +#define MICROPY_HW_CLK_PLLQ (9) + +// From the reference manual, for 2.7V to 3.6V +// 151-180 MHz => 5 wait states +// 181-210 MHz => 6 wait states +// 211-216 MHz => 7 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states + +// UART config +#define MICROPY_HW_UART2_TX (pin_D5) +#define MICROPY_HW_UART2_RX (pin_D6) +#define MICROPY_HW_UART2_RTS (pin_D4) +#define MICROPY_HW_UART2_CTS (pin_D3) +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART6_TX (pin_G14) +#define MICROPY_HW_UART6_RX (pin_G9) +#define MICROPY_HW_UART_REPL PYB_UART_3 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C3_SCL (pin_H7) +#define MICROPY_HW_I2C3_SDA (pin_H8) + +// SPI +#define MICROPY_HW_SPI3_NSS (pin_A4) +#define MICROPY_HW_SPI3_SCK (pin_B3) +#define MICROPY_HW_SPI3_MISO (pin_B4) +#define MICROPY_HW_SPI3_MOSI (pin_B5) + +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_B0) // green +#define MICROPY_HW_LED2 (pin_B7) // blue +#define MICROPY_HW_LED3 (pin_B14) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk new file mode 100644 index 0000000000..160218fd33 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk @@ -0,0 +1,6 @@ +MCU_SERIES = f7 +CMSIS_MCU = STM32F746xx +AF_FILE = boards/stm32f746_af.csv +LD_FILES = boards/stm32f746.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F746ZG/pins.csv b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv new file mode 100644 index 0000000000..aa5143e8c5 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F746ZG/pins.csv @@ -0,0 +1,68 @@ +A0,PA3 +A1,PC0 +A2,PC3 +A3,PF3 +A4,PF5 +A5,PF10 +D0,PG9 +D1,PG14 +D2,PF15 +D3,PE13 +D4,PF14 +D5,PE11 +D6,PE9 +D7,PF13 +D8,PF12 +D9,PD15 +D10,PD14 +D11,PA7 +D12,PA6 +D13,PA5 +D14,PB9 +D15,PB8 +D16,PC6 +D17,PB15 +D18,PB13 +D19,PB12 +D20,PA15 +D21,PC7 +D22,PB5 +D23,PB3 +D24,PA4 +D25,PB4 +LED1,PB0 +LED2,PB7 +LED3,PB14 +SW,PC13 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +EXT_SDA,PB9 +EXT_SCL,PB8 +EXT_RST,PG3 +SD_SW,PC13 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PA9 +USB_ID,PA10 +USB_DM,PA11 +USB_DP,PA12 +VCP_TX,PD8 +VCP_RX,PD9 +UART2_TX,PD5 +UART2_RX,PD6 +UART2_RTS,PD4 +UART2_CTS,PD3 +UART6_TX,PG14 +UART6_RX,PG9 +SPI_B_NSS,PA4 +SPI_B_SCK,PB3 +SPI_B_MOSI,PB5 diff --git a/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h new file mode 100644 index 0000000000..a019ee4ce9 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h @@ -0,0 +1,427 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_conf.h + * @author MCD Application Team + * @version V1.0.1 + * @date 25-June-2015 + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7xx_HAL_CONF_H +#define __STM32F7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_CEC_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SPDIFRX_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ + + +/* ########################## Timeout Configuration ######################### */ +/** + * @brief This is the HAL configuration section + */ +#define HAL_ACCURATE_TIMEOUT_ENABLED 0 +#define HAL_TIMEOUT_VALUE 0x1FFFFFF + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define ART_ACCLERATOR_ENABLE 1 /* To enable instruction cache and prefetch */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2 +#define MAC_ADDR1 1 +#define MAC_ADDR2 0 +#define MAC_ADDR3 0 +#define MAC_ADDR4 0 +#define MAC_ADDR5 0 + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)5) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)5) /* 5 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ +/* LAN8742A PHY Address*/ +#define LAN8742A_PHY_ADDRESS 0x00 +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x00000FFF) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFF) + +#define PHY_READ_TO ((uint32_t)0x0000FFFF) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFF) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x10) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x11) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x12) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f7xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f7xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f7xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f7xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f7xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f7xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f7xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f7xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f7xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f7xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f7xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f7xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f7xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f7xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f7xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f7xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f7xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f7xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f7xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f7xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f7xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32f7xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f7xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f7xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32f7xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f7xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f7xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f7xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f7xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32f7xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f7xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f7xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f7xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f7xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f7xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f7xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f7xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f7xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f7xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/NUCLEO_F767ZI/board_init.c b/ports/stm32/boards/NUCLEO_F767ZI/board_init.c new file mode 100644 index 0000000000..7d25a445d7 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_F767ZI/board_init.c @@ -0,0 +1,8 @@ +#include "py/mphal.h" + +void NUCLEO_F767ZI_board_early_init(void) { + // Turn off the USB switch + #define USB_PowerSwitchOn pin_G6 + mp_hal_pin_output(USB_PowerSwitchOn); + mp_hal_pin_low(USB_PowerSwitchOn); +} diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index 8952bce82f..3f23d77d48 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -8,16 +8,13 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) + +#define MICROPY_BOARD_EARLY_INIT NUCLEO_F767ZI_board_early_init +void NUCLEO_F767ZI_board_early_init(void); // HSE is 25MHz // VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz @@ -58,6 +55,12 @@ #define MICROPY_HW_SPI3_MISO (pin_B4) #define MICROPY_HW_SPI3_MOSI (pin_B5) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_C13) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) @@ -72,5 +75,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk index ba28a16e1e..b79ee7da20 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk @@ -2,4 +2,6 @@ MCU_SERIES = f7 CMSIS_MCU = STM32F767xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32f767_af.csv -LD_FILE = boards/stm32f767.ld +LD_FILES = boards/stm32f767.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv index 897b1473e7..3cae615dab 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/pins.csv +++ b/ports/stm32/boards/NUCLEO_F767ZI/pins.csv @@ -4,6 +4,9 @@ A2,PC3 A3,PF3 A4,PF5 A5,PF10 +A6,PB1 +A7,PC2 +A8,PF4 D0,PG9 D1,PG14 D2,PF15 @@ -51,10 +54,11 @@ LCD_SCL,PH7 OTG_FS_POWER,PD5 OTG_FS_OVER_CURRENT,PD4 OTG_HS_OVER_CURRENT,PE3 -USB_VBUS,PJ12 +USB_VBUS,PA9 USB_ID,PA10 USB_DM,PA11 USB_DP,PA12 +USB_POWER,PG6 VCP_TX,PD8 VCP_RX,PD9 UART2_TX,PD5 diff --git a/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h index e1aa4578d5..a019ee4ce9 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_H743ZI/board_init.c b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c new file mode 100644 index 0000000000..04149c37b8 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c @@ -0,0 +1,8 @@ +#include "py/mphal.h" + +void NUCLEO_H743ZI_board_early_init(void) { + // Turn off the USB switch + #define USB_PowerSwitchOn pin_G6 + mp_hal_pin_output(USB_PowerSwitchOn); + mp_hal_pin_low(USB_PowerSwitchOn); +} diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h new file mode 100644 index 0000000000..117e7f3f60 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -0,0 +1,65 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO_H743ZI" +#define MICROPY_HW_MCU_NAME "STM32H743" + +#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_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (1) + +#define MICROPY_BOARD_EARLY_INIT NUCLEO_H743ZI_board_early_init +void NUCLEO_H743ZI_board_early_init(void); + +// The board has an 8MHz HSE, the following gives 400MHz CPU speed +#define MICROPY_HW_CLK_PLLM (4) +#define MICROPY_HW_CLK_PLLN (400) +#define MICROPY_HW_CLK_PLLP (2) +#define MICROPY_HW_CLK_PLLQ (4) +#define MICROPY_HW_CLK_PLLR (2) + +// 4 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// UART config +#define MICROPY_HW_UART3_TX (pin_D8) +#define MICROPY_HW_UART3_RX (pin_D9) +#define MICROPY_HW_UART_REPL PYB_UART_3 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C2_SCL (pin_F1) +#define MICROPY_HW_I2C2_SDA (pin_F0) + +// SPI +//#define MICROPY_HW_SPI2_NSS (pin_I0) +//#define MICROPY_HW_SPI2_SCK (pin_I1) +//#define MICROPY_HW_SPI2_MISO (pin_B14) +//#define MICROPY_HW_SPI2_MOSI (pin_B15) + +// USRSW is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LEDs +#define MICROPY_HW_LED1 (pin_B0) // green +#define MICROPY_HW_LED2 (pin_B7) // blue +#define MICROPY_HW_LED3 (pin_B14) // red +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) + +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_G2) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk new file mode 100644 index 0000000000..4d3455441f --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = h7 +CMSIS_MCU = STM32H743xx +MICROPY_FLOAT_IMPL = double +AF_FILE = boards/stm32h743_af.csv +LD_FILES = boards/stm32h743.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08040000 diff --git a/ports/stm32/boards/NUCLEO_H743ZI/pins.csv b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv new file mode 100644 index 0000000000..30910c4dd5 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv @@ -0,0 +1,63 @@ +A0,PA0 +A1,PF10 +A2,PF9 +A3,PF8 +A4,PF7 +A5,PF6 +D0,PC7 +D1,PC6 +D2,PG6 +D3,PB4 +D4,PG7 +D5,PA8 +D6,PH6 +D7,PI3 +D8,PI2 +D9,PA15 +D10,PI0 +D11,PB15 +D12,PB14 +D13,PI1 +D14,PB9 +D15,PB8 +DAC1,PA4 +DAC2,PA5 +LED1,PB0 +LED2,PB7 +LED3,PB14 +SW,PC13 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +I2C1_SDA,PB9 +I2C1_SCL,PB8 +I2C2_SDA,PF0 +I2C2_SCL,PF1 +EXT_RST,PG3 +SD_D0,PC8 +SD_D1,PC9 +SD_D2,PC10 +SD_D3,PC11 +SD_CMD,PD2 +SD_CK,PC12 +SD_SW,PG2 +LCD_BL_CTRL,PK3 +LCD_INT,PI13 +LCD_SDA,PH8 +LCD_SCL,PH7 +OTG_FS_POWER,PD5 +OTG_FS_OVER_CURRENT,PD4 +OTG_HS_OVER_CURRENT,PE3 +USB_VBUS,PJ12 +USB_ID,PA8 +USB_DM,PA11 +USB_DP,PA12 +UART1_TX,PA9 +UART1_RX,PA10 +UART5_TX,PC12 +UART5_RX,PD2 +UART3_TX,PD8 +UART3_RX,PD9 diff --git a/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h new file mode 100644 index 0000000000..97b141d49f --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h @@ -0,0 +1,434 @@ +/** + ****************************************************************************** + * @file stm32h7xx_hal_conf_template.h + * @author MCD Application Team + * @version V1.2.0 + * @date 29-December-2017 + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32h7xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32H7xx_HAL_CONF_H +#define __STM32H7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CEC_MODULE_ENABLED +#define HAL_COMP_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_CRYP_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DCMI_MODULE_ENABLED +#define HAL_DFSDM_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_DMA2D_MODULE_ENABLED +#define HAL_ETH_MODULE_ENABLED +#define HAL_FDCAN_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_HASH_MODULE_ENABLED +#define HAL_HCD_MODULE_ENABLED +#define HAL_HRTIM_MODULE_ENABLED +#define HAL_HSEM_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +#define HAL_IRDA_MODULE_ENABLED +#define HAL_IWDG_MODULE_ENABLED +#define HAL_JPEG_MODULE_ENABLED +#define HAL_LPTIM_MODULE_ENABLED +#define HAL_LTDC_MODULE_ENABLED +#define HAL_MDIOS_MODULE_ENABLED +#define HAL_MDMA_MODULE_ENABLED +#define HAL_MMC_MODULE_ENABLED +#define HAL_NAND_MODULE_ENABLED +#define HAL_NOR_MODULE_ENABLED +#define HAL_OPAMP_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_QSPI_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SAI_MODULE_ENABLED +#define HAL_SD_MODULE_ENABLED +#define HAL_SDRAM_MODULE_ENABLED +#define HAL_SMARTCARD_MODULE_ENABLED +#define HAL_SMBUS_MODULE_ENABLED +#define HAL_SPDIFRX_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_SRAM_MODULE_ENABLED +#define HAL_SWPMI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) +#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal oscillator (CSI) default value. + * This value is the default CSI value after Reset. + */ +#if !defined (CSI_VALUE) + #define CSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* CSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)64000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External clock in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */ + +/* ########################### Ethernet Configuration ######################### */ +#define ETH_TX_DESC_CNT 4 /* number of Ethernet Tx DMA descriptors */ +#define ETH_RX_DESC_CNT 4 /* number of Ethernet Rx DMA descriptors */ + +#define ETH_MAC_ADDR0 ((uint8_t)0x02) +#define ETH_MAC_ADDR1 ((uint8_t)0x00) +#define ETH_MAC_ADDR2 ((uint8_t)0x00) +#define ETH_MAC_ADDR3 ((uint8_t)0x00) +#define ETH_MAC_ADDR4 ((uint8_t)0x00) +#define ETH_MAC_ADDR5 ((uint8_t)0x00) + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* ################## SPI peripheral configuration ########################## */ +/** + * @brief Used to activate CRC feature inside HAL SPI Driver + * Activated (1U): CRC code is compiled within HAL SPI driver + * Deactivated (0U): CRC code excluded from HAL SPI driver + */ + +#define USE_SPI_CRC 1U + + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32h7xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32h7xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32h7xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32h7xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32h7xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32h7xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32h7xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32h7xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32h7xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32h7xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_FDCAN_MODULE_ENABLED + #include "stm32h7xx_hal_fdcan.h" +#endif /* HAL_FDCAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32h7xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32h7xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32h7xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32h7xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32h7xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32h7xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HRTIM_MODULE_ENABLED + #include "stm32h7xx_hal_hrtim.h" +#endif /* HAL_HRTIM_MODULE_ENABLED */ + +#ifdef HAL_HSEM_MODULE_ENABLED + #include "stm32h7xx_hal_hsem.h" +#endif /* HAL_HSEM_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32h7xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32h7xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32h7xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32h7xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32h7xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32h7xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_JPEG_MODULE_ENABLED + #include "stm32h7xx_hal_jpeg.h" +#endif /* HAL_JPEG_MODULE_ENABLED */ + +#ifdef HAL_MDIOS_MODULE_ENABLED + #include "stm32h7xx_hal_mdios.h" +#endif /* HAL_MDIOS_MODULE_ENABLED */ + +#ifdef HAL_MDMA_MODULE_ENABLED + #include "stm32h7xx_hal_mdma.h" +#endif /* HAL_MDMA_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED + #include "stm32h7xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32h7xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED +#include "stm32h7xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32h7xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32h7xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32h7xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32h7xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32h7xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32h7xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32h7xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32h7xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32h7xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32h7xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32h7xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32h7xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32h7xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32h7xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32h7xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32h7xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32h7xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32h7xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32h7xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32h7xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32H7xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h index f2474619fe..0d5dab3945 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.h @@ -3,9 +3,8 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_USB (1) // MSI is used and is 4MHz #define MICROPY_HW_CLK_PLLM (1) @@ -51,3 +50,6 @@ #define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo #define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) + +// USB config +#define MICROPY_HW_USB_FS (1) diff --git a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk index abb4a35707..38ae5af212 100644 --- a/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_L476RG/mpconfigboard.mk @@ -1,5 +1,6 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv -LD_FILE = boards/stm32l476xg.ld -TEXT_ADDR = 0x08004000 +LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 diff --git a/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h index 9348e06790..6bfb28118a 100755 --- a/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_L476RG/stm32l4xx_hal_conf.h @@ -45,7 +45,6 @@ extern "C" { #endif -#define USE_USB_FS /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h index 5ede682647..a56f6f79df 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h @@ -1,20 +1,13 @@ -#define STM32E407 - #define MICROPY_HW_BOARD_NAME "OLIMEX STM32-E407" #define MICROPY_HW_MCU_NAME "STM32F407" #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) @@ -59,6 +52,12 @@ #define MICROPY_HW_SPI2_MISO (pin_B14) #define MICROPY_HW_SPI2_MOSI (pin_B15) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) @@ -76,5 +75,6 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk index ece09caa13..b154dcfbac 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F407xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/OLIMEX_E407/pins.csv b/ports/stm32/boards/OLIMEX_E407/pins.csv index 6b91f74ae4..81a9bcb853 100644 --- a/ports/stm32/boards/OLIMEX_E407/pins.csv +++ b/ports/stm32/boards/OLIMEX_E407/pins.csv @@ -82,4 +82,5 @@ PD13,PD13 PD14,PD14 PD15,PD15 PA0,PA0 - +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h index b84b0a8920..24cc9228b8 100644 --- a/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h index 090ba4cf1b..60a6980aaf 100644 --- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.h @@ -5,14 +5,10 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) -#define MICROPY_HW_ENABLE_RNG (0) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) @@ -81,6 +77,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) // MMA accelerometer config diff --git a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk index 71b3b19d65..df95065225 100644 --- a/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBLITEV10/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F411xE AF_FILE = boards/stm32f411_af.csv -LD_FILE = boards/stm32f411.ld +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h index 4ee8e72769..4e96f785ad 100644 --- a/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBLITEV10/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.h b/ports/stm32/boards/PYBV10/mpconfigboard.h index c06022a34d..3439f5a0fb 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBV10/mpconfigboard.h @@ -5,14 +5,12 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -67,8 +65,12 @@ #define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 // CAN busses -#define MICROPY_HW_CAN1_NAME "YA" // CAN1 on RX,TX = Y3,Y4 = PB8,PB9 -#define MICROPY_HW_CAN2_NAME "YB" // CAN2 on RX,TX = Y5,Y6 = PB12,PB13 +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_B3) @@ -92,6 +94,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.mk b/ports/stm32/boards/PYBV10/mpconfigboard.mk index 5734c66904..40972b3850 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV10/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h index 3d92522644..4f18ac81e3 100644 --- a/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV10/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.h b/ports/stm32/boards/PYBV11/mpconfigboard.h index c69e52cc50..2c75d0e64f 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.h +++ b/ports/stm32/boards/PYBV11/mpconfigboard.h @@ -5,14 +5,12 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 12MHz #define MICROPY_HW_CLK_PLLM (12) @@ -67,8 +65,12 @@ #define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 // CAN busses -#define MICROPY_HW_CAN1_NAME "YA" // CAN1 on RX,TX = Y3,Y4 = PB8,PB9 -#define MICROPY_HW_CAN2_NAME "YB" // CAN2 on RX,TX = Y5,Y6 = PB12,PB13 +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_B3) @@ -92,6 +94,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.mk b/ports/stm32/boards/PYBV11/mpconfigboard.mk index 5734c66904..40972b3850 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV11/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h index b84b0a8920..24cc9228b8 100644 --- a/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV11/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.h b/ports/stm32/boards/PYBV3/mpconfigboard.h index 1f49af4da1..3e457c5e21 100644 --- a/ports/stm32/boards/PYBV3/mpconfigboard.h +++ b/ports/stm32/boards/PYBV3/mpconfigboard.h @@ -5,14 +5,11 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -59,6 +56,12 @@ #define MICROPY_HW_SPI2_MISO (pin_B14) // Y7 #define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 + // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_A13) #define MICROPY_HW_USRSW_PULL (GPIO_PULLUP) @@ -82,6 +85,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_SET) // USB VBUS detect pin +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) // MMA accelerometer config diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.mk b/ports/stm32/boards/PYBV3/mpconfigboard.mk index 5734c66904..40972b3850 100644 --- a/ports/stm32/boards/PYBV3/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV3/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBV3/pins.csv b/ports/stm32/boards/PYBV3/pins.csv index b20bd4ffbd..1ddc3f52da 100644 --- a/ports/stm32/boards/PYBV3/pins.csv +++ b/ports/stm32/boards/PYBV3/pins.csv @@ -44,3 +44,5 @@ SD_D3,PC11 SD_CK,PC12 SD_CMD,PD2 UART1_TX,PA9 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h index d3df51c101..daf9b63cec 100644 --- a/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.h b/ports/stm32/boards/PYBV4/mpconfigboard.h index 2a4829c3e3..8c05644f6d 100644 --- a/ports/stm32/boards/PYBV4/mpconfigboard.h +++ b/ports/stm32/boards/PYBV4/mpconfigboard.h @@ -5,14 +5,12 @@ #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) #define MICROPY_HW_HAS_MMA7660 (1) -#define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -64,8 +62,12 @@ #define MICROPY_HW_SPI2_MOSI (pin_B15) // Y8 // CAN busses -#define MICROPY_HW_CAN1_NAME "YA" // CAN1 on RX,TX = Y3,Y4 = PB8,PB9 -#define MICROPY_HW_CAN2_NAME "YB" // CAN2 on RX,TX = Y5,Y6 = PB12,PB13 +#define MICROPY_HW_CAN1_NAME "YA" +#define MICROPY_HW_CAN1_TX (pin_B9) // Y4 +#define MICROPY_HW_CAN1_RX (pin_B8) // Y3 +#define MICROPY_HW_CAN2_NAME "YB" +#define MICROPY_HW_CAN2_TX (pin_B13) // Y6 +#define MICROPY_HW_CAN2_RX (pin_B12) // Y5 // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_B3) @@ -89,6 +91,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.mk b/ports/stm32/boards/PYBV4/mpconfigboard.mk index 5734c66904..40972b3850 100644 --- a/ports/stm32/boards/PYBV4/mpconfigboard.mk +++ b/ports/stm32/boards/PYBV4/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F405xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h index d3df51c101..daf9b63cec 100644 --- a/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/PYBV4/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F411DISC/mpconfigboard.h b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h index 1488cd7640..13172333b7 100644 --- a/ports/stm32/boards/STM32F411DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.h @@ -3,16 +3,9 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) -#define MICROPY_HW_ENABLE_RNG (0) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (5) @@ -66,5 +59,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk index 71b3b19d65..df95065225 100644 --- a/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F411DISC/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F411xE AF_FILE = boards/stm32f411_af.csv -LD_FILE = boards/stm32f411.ld +LD_FILES = boards/stm32f411.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F411DISC/pins.csv b/ports/stm32/boards/STM32F411DISC/pins.csv index 96077d54d4..a747aef3ef 100644 --- a/ports/stm32/boards/STM32F411DISC/pins.csv +++ b/ports/stm32/boards/STM32F411DISC/pins.csv @@ -82,3 +82,5 @@ LED_ORANGE,PD13 LED_RED,PD14 LED_BLUE,PD15 SW,PA0 +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h index 921cbe5fe1..8f0b663811 100644 --- a/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h index fc07020252..be25d2e772 100644 --- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h @@ -3,16 +3,9 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -56,6 +49,12 @@ //#define MICROPY_HW_SPI6_MISO (pin_G12) //#define MICROPY_HW_SPI6_MOSI (pin_G14) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) @@ -69,5 +68,7 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_B13) #define MICROPY_HW_USB_OTG_ID_PIN (pin_B12) diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk index 1bbf808b69..d19a35c316 100644 --- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F429xx AF_FILE = boards/stm32f429_af.csv -LD_FILE = boards/stm32f429.ld +LD_FILES = boards/stm32f429.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h index 4f5962dcbd..5b5a8a3e43 100644 --- a/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F429DISC/stm32f4xx_hal_conf.h @@ -46,9 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_HS -#define USE_USB_HS_IN_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.h b/ports/stm32/boards/STM32F439/mpconfigboard.h index eca79bf582..4ac5b32138 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.h +++ b/ports/stm32/boards/STM32F439/mpconfigboard.h @@ -1,18 +1,12 @@ #define MICROPY_HW_BOARD_NAME "CustomPCB" #define MICROPY_HW_MCU_NAME "STM32F439" -#define MICROPY_HW_HAS_SWITCH (0) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) //works with no SD card too -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // SD card detect switch #if MICROPY_HW_HAS_SDCARD @@ -27,6 +21,9 @@ #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) //divide PLL clock by this to get core clock #define MICROPY_HW_CLK_PLLQ (8) //divide core clock by this to get 48MHz +// USB config +#define MICROPY_HW_USB_FS (1) + // UART config #define MICROPY_HW_UART1_TX (pin_A9) #define MICROPY_HW_UART1_RX (pin_A10) @@ -52,7 +49,7 @@ #define MICROPY_HW_SPI1_SCK (pin_A5) #define MICROPY_HW_SPI1_MISO (pin_A6) #define MICROPY_HW_SPI1_MOSI (pin_A7) -#if defined(USE_USB_HS_IN_FS) +#if MICROPY_HW_USB_HS_IN_FS // The HS USB uses B14 & B15 for D- and D+ #else #define MICROPY_HW_SPI2_NSS (pin_B12) @@ -77,6 +74,12 @@ //#define MICROPY_HW_SPI6_MISO (pin_G12) //#define MICROPY_HW_SPI6_MOSI (pin_G14) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.mk b/ports/stm32/boards/STM32F439/mpconfigboard.mk index 0c30c06a30..ca97acbf61 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F439/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F439xx AF_FILE = boards/stm32f439_af.csv -LD_FILE = boards/stm32f439.ld +LD_FILES = boards/stm32f439.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h index d121b18c5e..5b5a8a3e43 100644 --- a/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F439/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h index 1058755158..3e4c8261cc 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h @@ -1,20 +1,12 @@ -#define STM32F4DISC - #define MICROPY_HW_BOARD_NAME "F4DISC" #define MICROPY_HW_MCU_NAME "STM32F407" #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (1) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (1) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 8MHz #define MICROPY_HW_CLK_PLLM (8) @@ -67,6 +59,12 @@ #define MICROPY_HW_SPI2_MISO (pin_B14) #define MICROPY_HW_SPI2_MOSI (pin_B15) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) @@ -82,5 +80,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk index ece09caa13..b154dcfbac 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f4 CMSIS_MCU = STM32F407xx AF_FILE = boards/stm32f405_af.csv -LD_FILE = boards/stm32f405.ld +LD_FILES = boards/stm32f405.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F4DISC/pins.csv b/ports/stm32/boards/STM32F4DISC/pins.csv index 4049fef7d9..a747aef3ef 100644 --- a/ports/stm32/boards/STM32F4DISC/pins.csv +++ b/ports/stm32/boards/STM32F4DISC/pins.csv @@ -82,4 +82,5 @@ LED_ORANGE,PD13 LED_RED,PD14 LED_BLUE,PD15 SW,PA0 - +USB_DM,PA11 +USB_DP,PA12 diff --git a/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h index d3df51c101..daf9b63cec 100644 --- a/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h index 50b9c1618f..8b29e5773e 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -8,15 +8,9 @@ #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // HSE is 25MHz // VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz @@ -49,6 +43,12 @@ #define MICROPY_HW_SPI2_MISO (pin_B14) #define MICROPY_HW_SPI2_MOSI (pin_B15) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) @@ -74,5 +74,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) /*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/ #define MICROPY_HW_USB_OTG_ID_PIN (pin_J12) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 99234e4cf1..873368ce5d 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk @@ -2,4 +2,6 @@ MCU_SERIES = f7 CMSIS_MCU = STM32F769xx MICROPY_FLOAT_IMPL = double AF_FILE = boards/stm32f767_af.csv -LD_FILE = boards/stm32f769.ld +LD_FILES = boards/stm32f769.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F769DISC/pins.csv b/ports/stm32/boards/STM32F769DISC/pins.csv index dcc2df2089..e68ed95366 100644 --- a/ports/stm32/boards/STM32F769DISC/pins.csv +++ b/ports/stm32/boards/STM32F769DISC/pins.csv @@ -55,3 +55,5 @@ UART1_TX,PA9 UART1_RX,PA10 UART5_TX,PC12 UART5_RX,PD2 +CAN2_TX,PB13 +CAN2_RX,PB12 diff --git a/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h index ce82549026..ff968bca99 100644 --- a/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h @@ -46,9 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_HS -#define USE_USB_HS_IN_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32F7DISC/board_init.c b/ports/stm32/boards/STM32F7DISC/board_init.c index 4530a47063..dd268fb9c0 100644 --- a/ports/stm32/boards/STM32F7DISC/board_init.c +++ b/ports/stm32/boards/STM32F7DISC/board_init.c @@ -3,13 +3,13 @@ void STM32F7DISC_board_early_init(void) { GPIO_InitTypeDef GPIO_InitStructure; - __GPIOK_CLK_ENABLE(); + __HAL_RCC_GPIOK_CLK_ENABLE(); // Turn off the backlight. LCD_BL_CTRL = PK3 GPIO_InitStructure.Pin = GPIO_PIN_3; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOK, &GPIO_InitStructure); HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET); } diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h index 44a39c0a1a..7b506a3056 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -1,20 +1,12 @@ -#define STM32F7DISC - #define MICROPY_HW_BOARD_NAME "F7DISC" #define MICROPY_HW_MCU_NAME "STM32F746" #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) #define MICROPY_HW_HAS_SDCARD (1) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) #define MICROPY_BOARD_EARLY_INIT STM32F7DISC_board_early_init void STM32F7DISC_board_early_init(void); @@ -57,6 +49,12 @@ void STM32F7DISC_board_early_init(void); #define MICROPY_HW_SPI2_MISO (pin_B14) #define MICROPY_HW_SPI2_MOSI (pin_B15) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) +#define MICROPY_HW_CAN2_TX (pin_B13) +#define MICROPY_HW_CAN2_RX (pin_B12) + // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_I11) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) @@ -77,6 +75,6 @@ void STM32F7DISC_board_early_init(void); // The Hardware VBUS detect only works on pin PA9. The STM32F7 Discovery uses // PA9 for VCP_TX functionality and connects the VBUS to pin J12 (so software // only detect). So we don't define the VBUS detect pin since that requires PA9. - +#define MICROPY_HW_USB_FS (1) /*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/ #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk index 7c6bc4584a..160218fd33 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk @@ -1,4 +1,6 @@ MCU_SERIES = f7 CMSIS_MCU = STM32F746xx AF_FILE = boards/stm32f746_af.csv -LD_FILE = boards/stm32f746.ld +LD_FILES = boards/stm32f746.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 diff --git a/ports/stm32/boards/STM32F7DISC/pins.csv b/ports/stm32/boards/STM32F7DISC/pins.csv index 1aa8a9b3a1..8b49003f7c 100644 --- a/ports/stm32/boards/STM32F7DISC/pins.csv +++ b/ports/stm32/boards/STM32F7DISC/pins.csv @@ -51,3 +51,5 @@ USB_DM,PA11 USB_DP,PA12 VCP_TX,PA9 VCP_RX,PB7 +CAN_TX,PB13 +CAN_RX,PB12 diff --git a/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h index 3fbfb43100..ff968bca99 100644 --- a/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/STM32L476DISC/bdev.c b/ports/stm32/boards/STM32L476DISC/bdev.c new file mode 100644 index 0000000000..01f06b8b1d --- /dev/null +++ b/ports/stm32/boards/STM32L476DISC/bdev.c @@ -0,0 +1,24 @@ +#include "storage.h" + +// External SPI flash uses standard SPI interface + +STATIC const mp_soft_spi_obj_t soft_spi_bus = { + .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, + .polarity = 0, + .phase = 0, + .sck = MICROPY_HW_SPIFLASH_SCK, + .mosi = MICROPY_HW_SPIFLASH_MOSI, + .miso = MICROPY_HW_SPIFLASH_MISO, +}; + +STATIC mp_spiflash_cache_t spi_bdev_cache; + +const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_SPI, + .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS, + .bus.u_spi.data = (void*)&soft_spi_bus, + .bus.u_spi.proto = &mp_soft_spi_proto, + .cache = &spi_bdev_cache, +}; + +spi_bdev_t spi_bdev; diff --git a/ports/stm32/boards/STM32L476DISC/board_init.c b/ports/stm32/boards/STM32L476DISC/board_init.c index fdc41c4019..eb44f320fe 100644 --- a/ports/stm32/boards/STM32L476DISC/board_init.c +++ b/ports/stm32/boards/STM32L476DISC/board_init.c @@ -1,10 +1,9 @@ #include "py/mphal.h" -#include "genhdr/pins.h" void STM32L476DISC_board_early_init(void) { // set SPI flash WP and HOLD pins high - mp_hal_pin_output(&pin_E14); - mp_hal_pin_output(&pin_E15); - mp_hal_pin_write(&pin_E14, 1); - mp_hal_pin_write(&pin_E15, 1); + mp_hal_pin_output(pin_E14); + mp_hal_pin_output(pin_E15); + mp_hal_pin_write(pin_E14, 1); + mp_hal_pin_write(pin_E15, 1); } diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h index 9dbadd5300..a35dee1182 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h @@ -4,18 +4,12 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_BOARD_NAME "L476-DISCO" #define MICROPY_HW_MCU_NAME "STM32L476" +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_FLASH (1) -#define MICROPY_HW_HAS_SDCARD (0) -#define MICROPY_HW_HAS_MMA7660 (0) -#define MICROPY_HW_HAS_LIS3DSH (0) -#define MICROPY_HW_HAS_LCD (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) -#define MICROPY_HW_ENABLE_TIMER (1) -#define MICROPY_HW_ENABLE_SERVO (0) -#define MICROPY_HW_ENABLE_DAC (0) -#define MICROPY_HW_ENABLE_CAN (0) +#define MICROPY_HW_ENABLE_USB (1) // use external SPI flash for storage #define MICROPY_HW_SPIFLASH_SIZE_BITS (128 * 1024 * 1024) @@ -24,6 +18,17 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_SPIFLASH_MOSI (pin_E12) #define MICROPY_HW_SPIFLASH_MISO (pin_E13) +// block device config for SPI flash +extern const struct _mp_spiflash_config_t spiflash_config; +extern struct _spi_bdev_t spi_bdev; +#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \ + (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \ + (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \ + spi_bdev_ioctl(&spi_bdev, (op), (arg)) \ +) +#define MICROPY_HW_BDEV_READBLOCKS(dest, bl, n) spi_bdev_readblocks(&spi_bdev, (dest), (bl), (n)) +#define MICROPY_HW_BDEV_WRITEBLOCKS(src, bl, n) spi_bdev_writeblocks(&spi_bdev, (src), (bl), (n)) + // MSI is used and is 4MHz #define MICROPY_HW_CLK_PLLM (1) #define MICROPY_HW_CLK_PLLN (40) @@ -52,6 +57,10 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_SPI2_MISO (pin_D3) #define MICROPY_HW_SPI2_MOSI (pin_D4) +// CAN busses +#define MICROPY_HW_CAN1_TX (pin_B9) +#define MICROPY_HW_CAN1_RX (pin_B8) + // Joystick is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) #define MICROPY_HW_USRSW_PULL (GPIO_NOPULL) @@ -65,4 +74,5 @@ void STM32L476DISC_board_early_init(void); #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_FS (1) // #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk index 72468d89ce..2cad9e2e56 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.mk @@ -1,6 +1,7 @@ MCU_SERIES = l4 CMSIS_MCU = STM32L476xx AF_FILE = boards/stm32l476_af.csv -LD_FILE = boards/stm32l476xg.ld -TEXT_ADDR = 0x08004000 +LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h index 9348e06790..6bfb28118a 100644 --- a/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h +++ b/ports/stm32/boards/STM32L476DISC/stm32l4xx_hal_conf.h @@ -45,7 +45,6 @@ extern "C" { #endif -#define USE_USB_FS /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h new file mode 100644 index 0000000000..6a17d74d3a --- /dev/null +++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.h @@ -0,0 +1,52 @@ +#define MICROPY_HW_BOARD_NAME "L496G-DISCO" +#define MICROPY_HW_MCU_NAME "STM32L496" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_USB (1) + +// MSI is used and is 4MHz, +// Resulting core frequency is 80MHz: +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// USART config +#define MICROPY_HW_UART2_TX (pin_A2) +#define MICROPY_HW_UART2_RX (pin_D6) +// USART 2 is connected to the virtual com port on the ST-LINK +#define MICROPY_HW_UART_REPL PYB_UART_2 +#define MICROPY_HW_UART_REPL_BAUD 115200 + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_G14) +#define MICROPY_HW_I2C1_SDA (pin_G13) +#define MICROPY_HW_I2C2_SCL (pin_H4) +#define MICROPY_HW_I2C2_SDA (pin_B14) + +// SPI busses +// -> To the arduino connector +#define MICROPY_HW_SPI1_NSS (pin_A15) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_B4) +#define MICROPY_HW_SPI1_MOSI (pin_B5) + +// Use Sel from joystick. Joystick is pulled low. Pressing the button makes the input go high. +#define MICROPY_HW_USRSW_PIN (pin_C13) +#define MICROPY_HW_USRSW_PULL (GPIO_PULLDOWN) +#define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_RISING) +#define MICROPY_HW_USRSW_PRESSED (1) + +// LED (The orange LED is controlled over MFX) +#define MICROPY_HW_LED1 (pin_B13) // Green +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) +// USB config +#define MICROPY_HW_USB_FS (1) +#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk new file mode 100644 index 0000000000..3a61746556 --- /dev/null +++ b/ports/stm32/boards/STM32L496GDISC/mpconfigboard.mk @@ -0,0 +1,7 @@ +MCU_SERIES = l4 +CMSIS_MCU = STM32L496xx +AF_FILE = boards/stm32l496_af.csv +LD_FILES = boards/stm32l496xg.ld boards/common_ifs.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08004000 +OPENOCD_CONFIG = boards/openocd_stm32l4.cfg diff --git a/ports/stm32/boards/STM32L496GDISC/pins.csv b/ports/stm32/boards/STM32L496GDISC/pins.csv new file mode 100644 index 0000000000..2ee054032b --- /dev/null +++ b/ports/stm32/boards/STM32L496GDISC/pins.csv @@ -0,0 +1,140 @@ +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PF0,PF0 +PF1,PF1 +PF2,PF2 +PF3,PF3 +PF4,PF4 +PF5,PF5 +PF6,PF6 +PF7,PF7 +PF8,PF8 +PF9,PF9 +PF10,PF10 +PF11,PF11 +PF12,PF12 +PF13,PF13 +PF14,PF14 +PF15,PF15 +PG0,PG0 +PG1,PG1 +PG2,PG2 +PG3,PG3 +PG4,PG4 +PG5,PG5 +PG6,PG6 +PG7,PG7 +PG8,PG8 +PG9,PG9 +PG10,PG10 +PG11,PG11 +PG12,PG12 +PG13,PG13 +PG14,PG14 +PG15,PG15 +PH0,PH0 +PH1,PH1 +PH2,PH2 +PH3,PH3 +PH4,PH4 +PH5,PH5 +PH6,PH6 +PH7,PH7 +PH8,PH8 +PH9,PH9 +PH10,PH10 +PH11,PH11 +PH12,PH12 +PH13,PH13 +PH14,PH14 +PH15,PH15 +PI0,PI0 +PI1,PI1 +PI2,PI2 +PI3,PI3 +PI4,PI4 +PI5,PI5 +PI6,PI6 +PI7,PI7 +PI8,PI8 +PI9,PI9 +PI10,PI10 +PI11,PI11 diff --git a/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h b/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h new file mode 100644 index 0000000000..884db5ef1a --- /dev/null +++ b/ports/stm32/boards/STM32L496GDISC/stm32l4xx_hal_conf.h @@ -0,0 +1,421 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_conf.h + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2018 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_HAL_CONF_H +#define __STM32L4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ + +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +/*#define HAL_CRYP_MODULE_ENABLED */ +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_COMP_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DCMI_MODULE_ENABLED */ +/*#define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_DFSDM_MODULE_ENABLED */ +/*#define HAL_DSI_MODULE_ENABLED */ +/*#define HAL_FIREWALL_MODULE_ENABLED */ +/*#define HAL_GFXMMU_MODULE_ENABLED */ +/*#define HAL_HCD_MODULE_ENABLED */ +/*#define HAL_HASH_MODULE_ENABLED */ +/*#define HAL_I2S_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +/*#define HAL_LTDC_MODULE_ENABLED */ +/*#define HAL_LCD_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +/*#define HAL_NAND_MODULE_ENABLED */ +/*#define HAL_NOR_MODULE_ENABLED */ +/*#define HAL_OPAMP_MODULE_ENABLED */ +/*#define HAL_OSPI_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SMBUS_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/*#define HAL_SRAM_MODULE_ENABLED */ +/*#define HAL_SWPMI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/*#define HAL_TSC_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + + /** + * @brief Internal High Speed oscillator (HSI48) value for USB FS, SDMMC and RNG. + * This internal oscillator is mainly dedicated to provide a high precision clock to + * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. + * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency + * which is subject to manufacturing process variations. + */ + #if !defined (HSI48_VALUE) + #define HSI48_VALUE ((uint32_t)48000000U) /*!< Value of the Internal High Speed oscillator for USB FS/SDMMC/RNG in Hz. + The real value my vary depending on manufacturing process variations.*/ + #endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/** + * @brief External clock source for SAI2 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI2_CLOCK_VALUE) + #define EXTERNAL_SAI2_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI2 External clock source in Hz*/ +#endif /* EXTERNAL_SAI2_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ + +#define USE_SPI_CRC 0 + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32l4xx_hal_rcc.h" + #include "stm32l4xx_hal_rcc_ex.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32l4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32l4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32l4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32l4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32l4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32l4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32l4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32l4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32l4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32l4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32l4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32l4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED + #include "stm32l4xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#ifdef HAL_FIREWALL_MODULE_ENABLED + #include "stm32l4xx_hal_firewall.h" +#endif /* HAL_FIREWALL_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32l4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32l4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32l4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32l4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32l4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32l4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32l4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32l4xx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32l4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32l4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED + #include "stm32l4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_OSPI_MODULE_ENABLED + #include "stm32l4xx_hal_ospi.h" +#endif /* HAL_OSPI_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32l4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32l4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32l4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32l4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32l4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32l4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32l4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32l4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32l4xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32l4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32l4xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32l4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32l4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32l4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32l4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32l4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32l4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32l4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_GFXMMU_MODULE_ENABLED + #include "stm32l4xx_hal_gfxmmu.h" +#endif /* HAL_GFXMMU_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_HAL_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/common_basic.ld b/ports/stm32/boards/common_basic.ld new file mode 100644 index 0000000000..2e428aa62c --- /dev/null +++ b/ports/stm32/boards/common_basic.ld @@ -0,0 +1,86 @@ +/* Memory layout for basic configuration: + + FLASH .isr_vector + FLASH .text + FLASH .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + +ENTRY(Reset_Handler) + +/* define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) /* .text* sections (code) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + /* *(.glue_7) */ /* glue arm to thumb code */ + /* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM AT> FLASH + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code and GC */ + } >RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/ports/stm32/boards/common_bl.ld b/ports/stm32/boards/common_bl.ld new file mode 100644 index 0000000000..52b2a677d7 --- /dev/null +++ b/ports/stm32/boards/common_bl.ld @@ -0,0 +1,86 @@ +/* Memory layout for bootloader configuration (this here describes the app part): + + FLASH_APP .isr_vector + FLASH_APP .text + FLASH_APP .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + +ENTRY(Reset_Handler) + +/* define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + + . = ALIGN(4); + } >FLASH_APP + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) /* .text* sections (code) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + /* *(.glue_7) */ /* glue arm to thumb code */ + /* *(.glue_7t) */ /* glue thumb to arm code */ + + . = ALIGN(4); + _etext = .; /* define a global symbol at end of code */ + } >FLASH_APP + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM AT> FLASH_APP + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code and GC */ + } >RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + . = . + _minimum_heap_size; + . = ALIGN(4); + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/ports/stm32/boards/common.ld b/ports/stm32/boards/common_ifs.ld similarity index 92% rename from ports/stm32/boards/common.ld rename to ports/stm32/boards/common_ifs.ld index e5dea49d08..74b2ffb419 100644 --- a/ports/stm32/boards/common.ld +++ b/ports/stm32/boards/common_ifs.ld @@ -1,3 +1,16 @@ +/* Memory layout for internal flash storage configuration: + + FLASH_ISR .isr_vector + + FLASH_TEXT .text + FLASH_TEXT .data + + RAM .data + RAM .bss + RAM .heap + RAM .stack +*/ + ENTRY(Reset_Handler) /* define output sections */ diff --git a/ports/stm32/boards/make-pins.py b/ports/stm32/boards/make-pins.py index 210c7b63c8..70f154fde0 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -16,6 +16,7 @@ SUPPORTED_FN = { 'UART' : ['RX', 'TX', 'CTS', 'RTS'], 'SPI' : ['NSS', 'SCK', 'MISO', 'MOSI'], 'SDMMC' : ['CK', 'CMD', 'D0', 'D1', 'D2', 'D3'], + 'CAN' : ['TX', 'RX'], } CONDITIONAL_VAR = { @@ -25,6 +26,7 @@ CONDITIONAL_VAR = { 'UART' : 'MICROPY_HW_UART{num}_TX', 'USART' : 'MICROPY_HW_UART{num}_TX', 'SDMMC' : 'MICROPY_HW_SDMMC{num}_CK', + 'CAN' : 'MICROPY_HW_CAN{num}_TX', } def parse_port_pin(name_str): @@ -207,18 +209,18 @@ class Pin(object): print("// ", end='') print('};') print('') - print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:s}, {:s}, {:d});'.format( + print('const pin_obj_t pin_{:s}_obj = PIN({:s}, {:d}, {:s}, {:s}, {:d});'.format( self.cpu_pin_name(), self.port_letter(), self.pin, self.alt_fn_name(null_if_0=True), self.adc_num_str(), self.adc_channel)) print('') def print_header(self, hdr_file): - hdr_file.write('extern const pin_obj_t pin_{:s};\n'. - format(self.cpu_pin_name())) + n = self.cpu_pin_name() + hdr_file.write('extern const pin_obj_t pin_{:s}_obj;\n'.format(n)) + hdr_file.write('#define pin_{:s} (&pin_{:s}_obj)\n'.format(n, n)) if self.alt_fn_count > 0: - hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. - format(self.cpu_pin_name())) + hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'.format(n)) def qstr_list(self): result = [] @@ -287,7 +289,7 @@ class Pins(object): for named_pin in named_pins: pin = named_pin.pin() if pin.is_board_pin(): - print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name())) + print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}_obj) }},'.format(named_pin.name(), pin.cpu_pin_name())) print('};') print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); @@ -305,13 +307,13 @@ class Pins(object): print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) for channel in range(17): if channel == 16: - print('#if defined(MCU_SERIES_L4)') + print('#if defined(STM32L4)') adc_found = False for named_pin in self.cpu_pins: pin = named_pin.pin() if (pin.is_board_pin() and (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)): - print(' &pin_{:s}, // {:d}'.format(pin.cpu_pin_name(), channel)) + print(' &pin_{:s}_obj, // {:d}'.format(pin.cpu_pin_name(), channel)) adc_found = True break if not adc_found: diff --git a/ports/stm32/boards/startup_stm32f0.s b/ports/stm32/boards/startup_stm32f0.s new file mode 100644 index 0000000000..eb5c4961e0 --- /dev/null +++ b/ports/stm32/boards/startup_stm32f0.s @@ -0,0 +1,303 @@ +/** + ****************************************************************************** + * @file startup_stm32f091xc.s + * @author MCD Application Team + * @brief STM32F091xC devices vector table for GCC toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M0 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m0 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr r0, =_estack + mov sp, r0 /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + ldr r0, =_sdata + ldr r1, =_edata + ldr r2, =_sidata + movs r3, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + +/* Zero fill the bss segment. */ + ldr r2, =_sbss + ldr r4, =_ebss + movs r3, #0 + b LoopFillZerobss + +FillZerobss: + str r3, [r2] + adds r2, r2, #4 + +LoopFillZerobss: + cmp r2, r4 + bcc FillZerobss + +/* Call the clock system intitialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + +LoopForever: + b LoopForever + + +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval : None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M0. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word 0 + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_VDDIO2_IRQHandler /* PVD and VDDIO2 through EXTI Line detect */ + .word RTC_IRQHandler /* RTC through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_CRS_IRQHandler /* RCC and CRS */ + .word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */ + .word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */ + .word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */ + .word TSC_IRQHandler /* TSC */ + .word DMA1_Ch1_IRQHandler /* DMA1 Channel 1 */ + .word DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler /* DMA1 Channel 2 and 3 & DMA2 Channel 1 and 2 */ + .word DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler /* DMA1 Channel 4 to 7 & DMA2 Channel 3 to 5 */ + .word ADC1_COMP_IRQHandler /* ADC1, COMP1 and COMP2 */ + .word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC */ + .word TIM7_IRQHandler /* TIM7 */ + .word TIM14_IRQHandler /* TIM14 */ + .word TIM15_IRQHandler /* TIM15 */ + .word TIM16_IRQHandler /* TIM16 */ + .word TIM17_IRQHandler /* TIM17 */ + .word I2C1_IRQHandler /* I2C1 */ + .word I2C2_IRQHandler /* I2C2 */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_8_IRQHandler /* USART3, USART4, USART5, USART6, USART7, USART8 */ + .word CEC_CAN_IRQHandler /* CEC and CAN */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_VDDIO2_IRQHandler + .thumb_set PVD_VDDIO2_IRQHandler,Default_Handler + + .weak RTC_IRQHandler + .thumb_set RTC_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_CRS_IRQHandler + .thumb_set RCC_CRS_IRQHandler,Default_Handler + + .weak EXTI0_1_IRQHandler + .thumb_set EXTI0_1_IRQHandler,Default_Handler + + .weak EXTI2_3_IRQHandler + .thumb_set EXTI2_3_IRQHandler,Default_Handler + + .weak EXTI4_15_IRQHandler + .thumb_set EXTI4_15_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak DMA1_Ch1_IRQHandler + .thumb_set DMA1_Ch1_IRQHandler,Default_Handler + + .weak DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler + .thumb_set DMA1_Ch2_3_DMA2_Ch1_2_IRQHandler,Default_Handler + + .weak DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler + .thumb_set DMA1_Ch4_7_DMA2_Ch3_5_IRQHandler,Default_Handler + + .weak ADC1_COMP_IRQHandler + .thumb_set ADC1_COMP_IRQHandler,Default_Handler + + .weak TIM1_BRK_UP_TRG_COM_IRQHandler + .thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak TIM14_IRQHandler + .thumb_set TIM14_IRQHandler,Default_Handler + + .weak TIM15_IRQHandler + .thumb_set TIM15_IRQHandler,Default_Handler + + .weak TIM16_IRQHandler + .thumb_set TIM16_IRQHandler,Default_Handler + + .weak TIM17_IRQHandler + .thumb_set TIM17_IRQHandler,Default_Handler + + .weak I2C1_IRQHandler + .thumb_set I2C1_IRQHandler,Default_Handler + + .weak I2C2_IRQHandler + .thumb_set I2C2_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_8_IRQHandler + .thumb_set USART3_8_IRQHandler,Default_Handler + + .weak CEC_CAN_IRQHandler + .thumb_set CEC_CAN_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/ports/stm32/boards/startup_stm32f4.s b/ports/stm32/boards/startup_stm32f4.s new file mode 100644 index 0000000000..3e29a79a56 --- /dev/null +++ b/ports/stm32/boards/startup_stm32f4.s @@ -0,0 +1,530 @@ +/** + ****************************************************************************** + * @file startup_stm32.S + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4/M7 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M4/M7. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_IRQHandler /* PVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FSMC_IRQHandler /* FSMC */ + .word SDIO_IRQHandler /* SDIO */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word CAN2_TX_IRQHandler /* CAN2 TX */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* CAN2 SCE */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word 0 /* CRYP crypto */ + .word HASH_RNG_IRQHandler /* Hash and Rng */ + .word FPU_IRQHandler /* FPU */ + .word UART7_IRQHandler /* UART7 */ + .word UART8_IRQHandler /* UART8 */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FSMC_IRQHandler + .thumb_set FSMC_IRQHandler,Default_Handler + + .weak SDIO_IRQHandler + .thumb_set SDIO_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak HASH_RNG_IRQHandler + .thumb_set HASH_RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/startup_stm32.S b/ports/stm32/boards/startup_stm32f7.s similarity index 75% rename from ports/stm32/startup_stm32.S rename to ports/stm32/boards/startup_stm32f7.s index a688cd0673..633ba01e93 100644 --- a/ports/stm32/startup_stm32.S +++ b/ports/stm32/boards/startup_stm32f7.s @@ -44,13 +44,7 @@ */ .syntax unified -#if defined(MCU_SERIES_F7) .cpu cortex-m7 -#elif defined(MCU_SERIES_F4) || defined(MCU_SERIES_L4) - .cpu cortex-m4 -#else - #error "Unknown MCU Series" -#endif .fpu softvfp .thumb @@ -166,11 +160,7 @@ g_pfnVectors: /* External Interrupts */ .word WWDG_IRQHandler /* Window WatchDog */ -#if defined(MCU_SERIES_L4) - .word PVD_PVM_IRQHandler /* PVD and PVM through EXTI line detection */ -#else .word PVD_IRQHandler /* PVD through EXTI Line detection */ -#endif .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ .word FLASH_IRQHandler /* FLASH */ @@ -180,16 +170,6 @@ g_pfnVectors: .word EXTI2_IRQHandler /* EXTI Line2 */ .word EXTI3_IRQHandler /* EXTI Line3 */ .word EXTI4_IRQHandler /* EXTI Line4 */ -#if defined(MCU_SERIES_L4) - .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */ - .word DMA1_Channel2_IRQHandler /* DMA1 Channel 2 */ - .word DMA1_Channel3_IRQHandler /* DMA1 Channel 3 */ - .word DMA1_Channel4_IRQHandler /* DMA1 Channel 4 */ - .word DMA1_Channel5_IRQHandler /* DMA1 Channel 5 */ - .word DMA1_Channel6_IRQHandler /* DMA1 Channel 6 */ - .word DMA1_Channel7_IRQHandler /* DMA1 Channel 7 */ - .word ADC1_2_IRQHandler /* ADC1 and ADC2 */ -#else .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ @@ -198,21 +178,14 @@ g_pfnVectors: .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ -#endif .word CAN1_TX_IRQHandler /* CAN1 TX */ .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ .word CAN1_SCE_IRQHandler /* CAN1 SCE */ .word EXTI9_5_IRQHandler /* External Line[9:5]s */ -#if defined(MCU_SERIES_L4) - .word TIM1_BRK_TIM15_IRQHandler /* TIM1 Break and TIM15 */ - .word TIM1_UP_TIM16_IRQHandler /* TIM1 Update and TIM16 */ - .word TIM1_TRG_COM_TIM17_IRQHandler /* TIM1 Trigger and Commutation and TIM17 */ -#else .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ -#endif .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ .word TIM2_IRQHandler /* TIM2 */ .word TIM3_IRQHandler /* TIM3 */ @@ -228,49 +201,20 @@ g_pfnVectors: .word USART3_IRQHandler /* USART3 */ .word EXTI15_10_IRQHandler /* External Line[15:10]s */ .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ -#if defined(MCU_SERIES_L4) - .word DFSDM3_IRQHandler /* Digital filter for sigma delta modulator 3 */ - .word TIM8_BRK_IRQHandler /* TIM8 Break */ - .word TIM8_UP_IRQHandler /* TIM8 Update */ - .word TIM8_TRG_COM_IRQHandler /* TIM8 Trigger and Commutation */ -#else .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ -#endif .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ -#if defined(MCU_SERIES_L4) - .word ADC3_IRQHandler /* ADC3 global interrupt */ -#else .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ -#endif -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) .word FMC_IRQHandler /* FMC */ .word SDMMC1_IRQHandler /* SDMMC1 */ -#else - .word FSMC_IRQHandler /* FSMC */ - .word SDIO_IRQHandler /* SDIO */ -#endif .word TIM5_IRQHandler /* TIM5 */ .word SPI3_IRQHandler /* SPI3 */ .word UART4_IRQHandler /* UART4 */ .word UART5_IRQHandler /* UART5 */ .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ .word TIM7_IRQHandler /* TIM7 */ -#if defined(MCU_SERIES_L4) - .word DMA2_Channel1_IRQHandler /* DMA2 Channel 1 */ - .word DMA2_Channel2_IRQHandler /* DMA2 Channel 2 */ - .word DMA2_Channel3_IRQHandler /* DMA2 Channel 3 */ - .word DMA2_Channel4_IRQHandler /* DMA2 Channel 4 */ - .word DMA2_Channel5_IRQHandler /* DMA2 Channel 5 */ - .word DFSDM0_IRQHandler /* Digital filter for sigma delta modulator 0 */ - .word DFSDM1_IRQHandler /* Digital filter for sigma delta modulator 1 */ - .word DFSDM2_IRQHandler /* Digital filter for sigma delta modulator 2 */ - .word COMP_IRQHandler /* Comporator thru EXTI line */ - .word LPTIM1_IRQHandler /* Low power timer 1 */ - .word LPTIM2_IRQHandler /* Low power timer 2 */ -#else .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ @@ -282,43 +226,21 @@ g_pfnVectors: .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ .word CAN2_SCE_IRQHandler /* CAN2 SCE */ -#endif .word OTG_FS_IRQHandler /* USB OTG FS */ -#if defined(MCU_SERIES_L4) - .word DMA2_Channel6_IRQHandler /* DMA2 Channel 6 */ - .word DMA2_Channel7_IRQHandler /* DMA2 Channel 7 */ - .word LPUART1_IRQHandler /* Low power UART */ - .word QUADSPI_IRQHandler /* Quad SPI */ -#else .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ .word USART6_IRQHandler /* USART6 */ -#endif .word I2C3_EV_IRQHandler /* I2C3 event */ .word I2C3_ER_IRQHandler /* I2C3 error */ -#if defined(MCU_SERIES_L4) - .word SAI1_IRQHandler /* Serial audio interface 1 */ - .word SAI2_IRQHandler /* Serial audio interface 2 */ - .word SWPMI1_IRQHandler /* Single wire protocole 1 */ - .word TSC_IRQHandler /* Touch sensig controller */ - .word LCD_IRQHandler /* LCD */ -#else .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ .word OTG_HS_IRQHandler /* USB OTG HS */ .word DCMI_IRQHandler /* DCMI */ -#endif .word 0 /* CRYP crypto */ -#if defined(MCU_SERIES_L4) - .word RNG_IRQHandler /* Random number generator */ -#else .word HASH_RNG_IRQHandler /* Hash and Rng */ -#endif .word FPU_IRQHandler /* FPU */ - -#if defined(MCU_SERIES_F7) .word UART7_IRQHandler /* UART7 */ .word UART8_IRQHandler /* UART8 */ .word SPI4_IRQHandler /* SPI4 */ @@ -341,7 +263,6 @@ g_pfnVectors: .word DFSDM1_FLT2_IRQHandler /* DFSDM1 filter 2 */ .word DFSDM1_FLT3_IRQHandler /* DFSDM1 filter 3 */ .word SDMMC2_IRQHandler /* SDMMC2 */ -#endif /******************************************************************************* * @@ -380,13 +301,8 @@ g_pfnVectors: .weak WWDG_IRQHandler .thumb_set WWDG_IRQHandler,Default_Handler -#if defined(MCU_SERIES_L4) - .weak PVD_PVM_IRQHandler - .thumb_set PVD_PVM_IRQHandler,Default_Handler -#else .weak PVD_IRQHandler .thumb_set PVD_IRQHandler,Default_Handler -#endif .weak TAMP_STAMP_IRQHandler .thumb_set TAMP_STAMP_IRQHandler,Default_Handler @@ -415,31 +331,6 @@ g_pfnVectors: .weak EXTI4_IRQHandler .thumb_set EXTI4_IRQHandler,Default_Handler -#if defined(MCU_SERIES_L4) - .weak DMA1_Channel1_IRQHandler - .thumb_set DMA1_Channel1_IRQHandler,Default_Handler - - .weak DMA1_Channel2_IRQHandler - .thumb_set DMA1_Channel2_IRQHandler,Default_Handler - - .weak DMA1_Channel3_IRQHandler - .thumb_set DMA1_Channel3_IRQHandler,Default_Handler - - .weak DMA1_Channel4_IRQHandler - .thumb_set DMA1_Channel4_IRQHandler,Default_Handler - - .weak DMA1_Channel5_IRQHandler - .thumb_set DMA1_Channel5_IRQHandler,Default_Handler - - .weak DMA1_Channel6_IRQHandler - .thumb_set DMA1_Channel6_IRQHandler,Default_Handler - - .weak DMA1_Channel7_IRQHandler - .thumb_set DMA1_Channel7_IRQHandler,Default_Handler - - .weak ADC1_2_IRQHandler - .thumb_set ADC1_2_IRQHandler,Default_Handler -#else .weak DMA1_Stream0_IRQHandler .thumb_set DMA1_Stream0_IRQHandler,Default_Handler @@ -463,7 +354,6 @@ g_pfnVectors: .weak ADC_IRQHandler .thumb_set ADC_IRQHandler,Default_Handler -#endif .weak CAN1_TX_IRQHandler .thumb_set CAN1_TX_IRQHandler,Default_Handler @@ -480,16 +370,6 @@ g_pfnVectors: .weak EXTI9_5_IRQHandler .thumb_set EXTI9_5_IRQHandler,Default_Handler -#if defined(MCU_SERIES_L4) - .weak TIM1_BRK_TIM15_IRQHandler - .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler - - .weak TIM1_UP_TIM16_IRQHandler - .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler - - .weak TIM1_TRG_COM_TIM17_IRQHandler - .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler -#else .weak TIM1_BRK_TIM9_IRQHandler .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler @@ -498,7 +378,6 @@ g_pfnVectors: .weak TIM1_TRG_COM_TIM11_IRQHandler .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler -#endif .weak TIM1_CC_IRQHandler .thumb_set TIM1_CC_IRQHandler,Default_Handler @@ -545,19 +424,6 @@ g_pfnVectors: .weak RTC_Alarm_IRQHandler .thumb_set RTC_Alarm_IRQHandler,Default_Handler -#if defined(MCU_SERIES_L4) - .weak DFSDM3_IRQHandler - .thumb_set DFSDM3_IRQHandler,Default_Handler - - .weak TIM8_BRK_IRQHandler - .thumb_set TIM8_BRK_IRQHandler,Default_Handler - - .weak TIM8_UP_IRQHandler - .thumb_set TIM8_UP_IRQHandler,Default_Handler - - .weak TIM8_TRG_COM_IRQHandler - .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler -#else .weak OTG_FS_WKUP_IRQHandler .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler @@ -569,32 +435,18 @@ g_pfnVectors: .weak TIM8_TRG_COM_TIM14_IRQHandler .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler -#endif .weak TIM8_CC_IRQHandler .thumb_set TIM8_CC_IRQHandler,Default_Handler -#if defined(MCU_SERIES_L4) - .weak ADC3_IRQHandler - .thumb_set ADC3_IRQHandler,Default_Handler -#else .weak DMA1_Stream7_IRQHandler .thumb_set DMA1_Stream7_IRQHandler,Default_Handler -#endif -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) .weak FMC_IRQHandler .thumb_set FMC_IRQHandler,Default_Handler .weak SDMMC1_IRQHandler .thumb_set SDMMC1_IRQHandler,Default_Handler -#else - .weak FSMC_IRQHandler - .thumb_set FSMC_IRQHandler,Default_Handler - - .weak SDIO_IRQHandler - .thumb_set SDIO_IRQHandler,Default_Handler -#endif .weak TIM5_IRQHandler .thumb_set TIM5_IRQHandler,Default_Handler @@ -614,40 +466,6 @@ g_pfnVectors: .weak TIM7_IRQHandler .thumb_set TIM7_IRQHandler,Default_Handler -#if defined(MCU_SERIES_L4) - .weak DMA2_Channel1_IRQHandler - .thumb_set DMA2_Channel1_IRQHandler,Default_Handler - - .weak DMA2_Channel2_IRQHandler - .thumb_set DMA2_Channel2_IRQHandler,Default_Handler - - .weak DMA2_Channel3_IRQHandler - .thumb_set DMA2_Channel3_IRQHandler,Default_Handler - - .weak DMA2_Channel4_IRQHandler - .thumb_set DMA2_Channel4_IRQHandler,Default_Handler - - .weak DMA2_Channel5_IRQHandler - .thumb_set DMA2_Channel5_IRQHandler,Default_Handler - - .weak DFSDM0_IRQHandler - .thumb_set DFSDM0_IRQHandler,Default_Handler - - .weak DFSDM1_IRQHandler - .thumb_set DFSDM1_IRQHandler,Default_Handler - - .weak DFSDM2_IRQHandler - .thumb_set DFSDM2_IRQHandler,Default_Handler - - .weak COMP_IRQHandler - .thumb_set COMP_IRQHandler,Default_Handler - - .weak LPTIM1_IRQHandler - .thumb_set LPTIM1_IRQHandler,Default_Handler - - .weak LPTIM2_IRQHandler - .thumb_set LPTIM2_IRQHandler,Default_Handler -#else .weak DMA2_Stream0_IRQHandler .thumb_set DMA2_Stream0_IRQHandler,Default_Handler @@ -680,24 +498,10 @@ g_pfnVectors: .weak CAN2_SCE_IRQHandler .thumb_set CAN2_SCE_IRQHandler,Default_Handler -#endif .weak OTG_FS_IRQHandler .thumb_set OTG_FS_IRQHandler,Default_Handler -#if defined(MCU_SERIES_L4) - .weak DMA2_Channel6_IRQHandler - .thumb_set DMA2_Channel6_IRQHandler,Default_Handler - - .weak DMA2_Channel7_IRQHandler - .thumb_set DMA2_Channel7_IRQHandler,Default_Handler - - .weak LPUART1_IRQHandler - .thumb_set LPUART1_IRQHandler,Default_Handler - - .weak QUADSPI_IRQHandler - .thumb_set QUADSPI_IRQHandler,Default_Handler -#else .weak DMA2_Stream5_IRQHandler .thumb_set DMA2_Stream5_IRQHandler,Default_Handler @@ -709,7 +513,6 @@ g_pfnVectors: .weak USART6_IRQHandler .thumb_set USART6_IRQHandler,Default_Handler -#endif .weak I2C3_EV_IRQHandler .thumb_set I2C3_EV_IRQHandler,Default_Handler @@ -717,25 +520,6 @@ g_pfnVectors: .weak I2C3_ER_IRQHandler .thumb_set I2C3_ER_IRQHandler,Default_Handler -#if defined(MCU_SERIES_L4) - .weak SAI1_IRQHandler - .thumb_set SAI1_IRQHandler,Default_Handler - - .weak SAI2_IRQHandler - .thumb_set SAI2_IRQHandler,Default_Handler - - .weak SWPMI1_IRQHandler - .thumb_set SWPMI1_IRQHandler,Default_Handler - - .weak TSC_IRQHandler - .thumb_set TSC_IRQHandler,Default_Handler - - .weak LCD_IRQHandler - .thumb_set LCD_IRQHandler,Default_Handler - - .weak RNG_IRQHandler - .thumb_set RNG_IRQHandler,Default_Handler -#else .weak OTG_HS_EP1_OUT_IRQHandler .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler @@ -753,11 +537,10 @@ g_pfnVectors: .weak HASH_RNG_IRQHandler .thumb_set HASH_RNG_IRQHandler,Default_Handler -#endif .weak FPU_IRQHandler .thumb_set FPU_IRQHandler,Default_Handler -#if defined(MCU_SERIES_F7) + .weak UART7_IRQHandler .thumb_set UART7_IRQHandler,Default_Handler @@ -817,6 +600,5 @@ g_pfnVectors: .weak SDMMC2_IRQHandler .thumb_set SDMMC2_IRQHandler,Default_Handler -#endif /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/startup_stm32h7.s b/ports/stm32/boards/startup_stm32h7.s new file mode 100644 index 0000000000..53d46205fd --- /dev/null +++ b/ports/stm32/boards/startup_stm32h7.s @@ -0,0 +1,763 @@ +/** + ****************************************************************************** + * @file startup_stm32h743xx.s + * @author MCD Application Team + * @version V1.2.0 + * @date 29-December-2017 + * @brief STM32H743xx Devices vector table for GCC based toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2017 STMicroelectronics

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

© COPYRIGHT 2017 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +.equ BootRAM, 0xF1E0F85F +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex-M4. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_PVM_IRQHandler /* PVD and PVM through EXTI line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */ + .word DMA1_Channel2_IRQHandler /* DMA1 Channel 2 */ + .word DMA1_Channel3_IRQHandler /* DMA1 Channel 3 */ + .word DMA1_Channel4_IRQHandler /* DMA1 Channel 4 */ + .word DMA1_Channel5_IRQHandler /* DMA1 Channel 5 */ + .word DMA1_Channel6_IRQHandler /* DMA1 Channel 6 */ + .word DMA1_Channel7_IRQHandler /* DMA1 Channel 7 */ + .word ADC1_2_IRQHandler /* ADC1 and ADC2 */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM15_IRQHandler /* TIM1 Break and TIM15 */ + .word TIM1_UP_TIM16_IRQHandler /* TIM1 Update and TIM16 */ + .word TIM1_TRG_COM_TIM17_IRQHandler /* TIM1 Trigger and Commutation and TIM17 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word DFSDM1_FLT3_IRQHandler /* Digital filter 3 for sigma delta modulator */ + .word TIM8_BRK_IRQHandler /* TIM8 Break */ + .word TIM8_UP_IRQHandler /* TIM8 Update */ + .word TIM8_TRG_COM_IRQHandler /* TIM8 Trigger and Commutation */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word ADC3_IRQHandler /* ADC3 global interrupt */ + .word FMC_IRQHandler /* FMC */ + .word SDMMC1_IRQHandler /* SDMMC1 */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Channel1_IRQHandler /* DMA2 Channel 1 */ + .word DMA2_Channel2_IRQHandler /* DMA2 Channel 2 */ + .word DMA2_Channel3_IRQHandler /* DMA2 Channel 3 */ + .word DMA2_Channel4_IRQHandler /* DMA2 Channel 4 */ + .word DMA2_Channel5_IRQHandler /* DMA2 Channel 5 */ + .word DFSDM1_FLT0_IRQHandler /* Digital filter 0 for sigma delta modulator */ + .word DFSDM1_FLT1_IRQHandler /* Digital filter 1 for sigma delta modulator */ + .word DFSDM1_FLT2_IRQHandler /* Digital filter 2 for sigma delta modulator */ + .word COMP_IRQHandler /* Comporator thru EXTI line */ + .word LPTIM1_IRQHandler /* Low power timer 1 */ + .word LPTIM2_IRQHandler /* Low power timer 2 */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Channel6_IRQHandler /* DMA2 Channel 6 */ + .word DMA2_Channel7_IRQHandler /* DMA2 Channel 7 */ + .word LPUART1_IRQHandler /* Low power UART */ + .word QUADSPI_IRQHandler /* Quad SPI */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word SAI1_IRQHandler /* Serial audio interface 1 */ + .word SAI2_IRQHandler /* Serial audio interface 2 */ + .word SWPMI1_IRQHandler /* Single wire protocole 1 */ + .word TSC_IRQHandler /* Touch sensig controller */ + .word LCD_IRQHandler /* LCD */ + .word 0 /* CRYP crypto */ + .word RNG_IRQHandler /* Random number generator */ + .word FPU_IRQHandler /* FPU */ + /* Following Handlers are only used on L496/4A6xx devices */ + .word CRS_IRQHandler /* HASH and CRS interrupt */ + .word I2C4_EV_IRQHandler /* I2C4 event interrupt */ + .word I2C4_ER_IRQHandler /* I2C4 error interrupt */ + .word DCMI_IRQHandler /* DCMI global interrupt */ + .word CAN2_TX_IRQHandler /* CAN2 TX interrupt */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 interrupt */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 interrupt */ + .word CAN2_SCE_IRQHandler /* CAN SCE interrupt */ + .word DMA2D_IRQHandler /* DMA2D global interrupt */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_PVM_IRQHandler + .thumb_set PVD_PVM_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + + .weak ADC1_2_IRQHandler + .thumb_set ADC1_2_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM15_IRQHandler + .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM16_IRQHandler + .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM17_IRQHandler + .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak DFSDM1_FLT3_IRQHandler + .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler + + .weak TIM8_BRK_IRQHandler + .thumb_set TIM8_BRK_IRQHandler,Default_Handler + + .weak TIM8_UP_IRQHandler + .thumb_set TIM8_UP_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_IRQHandler + .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak ADC3_IRQHandler + .thumb_set ADC3_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Channel1_IRQHandler + .thumb_set DMA2_Channel1_IRQHandler,Default_Handler + + .weak DMA2_Channel2_IRQHandler + .thumb_set DMA2_Channel2_IRQHandler,Default_Handler + + .weak DMA2_Channel3_IRQHandler + .thumb_set DMA2_Channel3_IRQHandler,Default_Handler + + .weak DMA2_Channel4_IRQHandler + .thumb_set DMA2_Channel4_IRQHandler,Default_Handler + + .weak DMA2_Channel5_IRQHandler + .thumb_set DMA2_Channel5_IRQHandler,Default_Handler + + .weak DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler + + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler + + .weak DFSDM1_FLT2_IRQHandler + .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler + + .weak COMP_IRQHandler + .thumb_set COMP_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Channel6_IRQHandler + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + + .weak DMA2_Channel7_IRQHandler + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak SAI2_IRQHandler + .thumb_set SAI2_IRQHandler,Default_Handler + + .weak SWPMI1_IRQHandler + .thumb_set SWPMI1_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak LCD_IRQHandler + .thumb_set LCD_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak DMA2D_IRQHandler + .thumb_set DMA2D_IRQHandler,Default_Handler +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/stm32f091_af.csv b/ports/stm32/boards/stm32f091_af.csv new file mode 100644 index 0000000000..38e134f8a9 --- /dev/null +++ b/ports/stm32/boards/stm32f091_af.csv @@ -0,0 +1,89 @@ +Port,Pin,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,,,,,,,,, +,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,,,,,,,,,ADC +PortA,PA0,,USART2_CTS,TIM2_CH1_ETR,TSC_G1_IO1,USART4_TX,,,COMP1_OUT,,,,,,,,,ADC1_IN0 +PortA,PA1,EVENTOUT,USART2_RTS,TIM2_CH2,TSC_G1_IO2,USART4_RX,TIM15_CH1N,,,,,,,,,,,ADC1_IN1 +PortA,PA2,TIM15_CH1,USART2_TX,TIM2_CH3,TSC_G1_IO3,,,,COMP2_OUT,,,,,,,,,ADC1_IN2 +PortA,PA3,TIM15_CH2,USART2_RX,TIM2_CH4,TSC_G1_IO4,,,,,,,,,,,,,ADC1_IN3 +PortA,PA4,SPI1_NSS/I2S1_WS,USART2_CK,,TSC_G2_IO1,TIM14_CH1,USART6_TX,,,,,,,,,,,ADC1_IN4 +PortA,PA5,SPI1_SCK/I2S1_CK,CEC,TIM2_CH1_ETR,TSC_G2_IO2,,USART6_RX,,,,,,,,,,,ADC1_IN5 +PortA,PA6,SPI1_MISO/I2S1_MCK,TIM3_CH1,TIM1_BKIN,TSC_G2_IO3,USART3_CTS,TIM16_CH1,EVENTOUT,COMP1_OUT,,,,,,,,,ADC1_IN6 +PortA,PA7,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM1_CH1N,TSC_G2_IO4,TIM14_CH1,TIM17_CH1,EVENTOUT,COMP2_OUT,,,,,,,,,ADC1_IN7 +PortA,PA8,MCO,USART1_CK,TIM1_CH1,EVENTOUT,CRS_SYNC,,,,,,,,,,,, +PortA,PA9,TIM15_BKIN,USART1_TX,TIM1_CH2,TSC_G4_IO1,I2C1_SCL,MCO,,,,,,,,,,, +PortA,PA10,TIM17_BKIN,USART1_RX,TIM1_CH3,TSC_G4_IO2,I2C1_SDA,,,,,,,,,,,, +PortA,PA11,EVENTOUT,USART1_CTS,TIM1_CH4,TSC_G4_IO3,CAN1_RX,I2C2_SCL,,COMP1_OUT,,,,,,,,, +PortA,PA12,EVENTOUT,USART1_RTS,TIM1_ETR,TSC_G4_IO4,CAN1_TX,I2C2_SDA,,COMP2_OUT,,,,,,,,, +PortA,PA13,SWDIO,IR_OUT,,,,,,,,,,,,,,, +PortA,PA14,SWCLK,USART2_TX,,,,,,,,,,,,,,, +PortA,PA15,SPI1_NSS/I2S1_WS,USART2_RX,TIM2_CH1_ETR,EVENTOUT,USART4_RTS,,,,,,,,,,,, +PortB,PB0,EVENTOUT,TIM3_CH3,TIM1_CH2N,TSC_G3_IO2,USART3_CK,,,,,,,,,,,,ADC1_IN8 +PortB,PB1,TIM14_CH1,TIM3_CH4,TIM1_CH3N,TSC_G3_IO3,USART3_RTS,,,,,,,,,,,,ADC1_IN9 +PortB,PB2,,,,TSC_G3_IO4,,,,,,,,,,,,, +PortB,PB3,SPI1_SCK/I2S1_CK,EVENTOUT,TIM2_CH2,TSC_G5_IO1,USART5_TX,,,,,,,,,, +PortB,PB4,SPI1_MISO/I2S1_MCK,TIM3_CH1,EVENTOUT,TSC_G5_IO2,USART5_RX,TIM17_BKIN,,,,,,,,, +PortB,PB5,SPI1_MOSI/I2S1_SD,TIM3_CH2,TIM16_BKIN,I2C1_SMBA,USART5_CK/USART5_RTS,,,,,,,,,, +PortB,PB6,USART1_TX,I2C1_SCL,TIM16_CH1N,TSC_G5_IO3,,,,,,,,,,, +PortB,PB7,USART1_RX,I2C1_SDA,TIM17_CH1N,TSC_G5_IO4,USART4_CTS,,,,,,,,,, +PortB,PB8,CEC,I2C1_SCL,TIM16_CH1,TSC_SYNC,CAN1_RX,,,,,,,,,, +PortB,PB9,IR_OUT,I2C1_SDA,TIM17_CH1,EVENTOUT,CAN1_TX,SPI2_NSS/I2S2_WS,,,,,,,,, +PortB,PB10,CEC,I2C2_SCL,TIM2_CH3,TSC_SYNC,USART3_TX,SPI2_SCK/I2S2_CK,,,,,,,,, +PortB,PB11,EVENTOUT,I2C2_SDA,TIM2_CH4,TSC_G6_IO1,USART3_RX,,,,,,,,,, +PortB,PB12,SPI2_NSS/I2S2_WS,EVENTOUT,TIM1_BKIN,TSC_G6_IO2,USART3_CK,TIM15_BKIN,,,,,,,,, +PortB,PB13,SPI2_SCK/I2S2_CK,,TIM1_CH1N,TSC_G6_IO3,USART3_CTS,I2C2_SCL,,,,,,,,, +PortB,PB14,SPI2_MISO/I2S2_MCK,TIM15_CH1,TIM1_CH2N,TSC_G6_IO4,USART3_RTS,I2C2_SDA,,,,,,,,, +PortB,PB15,SPI2_MOSI/I2S2_SD,TIM15_CH2,TIM1_CH3N,TIM15_CH1N,,,,,,,,,,, +PortC,PC0,EVENTOUT,USART7_TX,USART6_TX,,,,,,,,,,,,,,ADC1_IN10 +PortC,PC1,EVENTOUT,USART7_RX,USART6_RX,,,,,,,,,,,,,,ADC1_IN11 +PortC,PC2,EVENTOUT,SPI2_MISO/I2S2_MCK,USART8_TX,,,,,,,,,,,,,,ADC1_IN12 +PortC,PC3,EVENTOUT,SPI2_MOSI/I2S2_SD,USART8_RX,,,,,,,,,,,,,,ADC1_IN13 +PortC,PC4,EVENTOUT,USART3_TX,,,,,,,,,,,,,,,ADC1_IN14 +PortC,PC5,TSC_G3_IO1,USART3_RX,,,,,,,,,,,,,,,ADC1_IN15 +PortC,PC6,TIM3_CH1,USART7_TX,,,,,,,,,,,,,,, +PortC,PC7,TIM3_CH2,USART7_RX,,,,,,,,,,,,,,, +PortC,PC8,TIM3_CH3,USART8_TX,,,,,,,,,,,,,,, +PortC,PC9,TIM3_CH4,USART8_RX,,,,,,,,,,,,,,, +PortC,PC10,USART4_TX,USART3_TX,,,,,,,,,,,,,,, +PortC,PC11,USART4_RX,USART3_RX,,,,,,,,,,,,,,, +PortC,PC12,USART4_CK,USART3_CK,USART5_TX,,,,,,,,,,,,,, +PortC,PC13,,,,,,,,,,,,,,,,, +PortC,PC14,,,,,,,,,,,,,,,,, +PortC,PC15,,,,,,,,,,,,,,,,, +PortD,PD0,CAN1_RX,SPI2_NSS/I2S2_WS,,,,,,,,,,,,,,, +PortD,PD1,CAN1_TX,SPI2_SCK/I2S2_CK,,,,,,,,,,,,,,, +PortD,PD2,TIM3_ETR,USART3_RTS,USART5_RX,,,,,,,,,,,,,, +PortD,PD3,USART2_CTS,SPI2_MISO/I2S2_MCK,,,,,,,,,,,,,,, +PortD,PD4,USART2_RTS,SPI2_MOSI/I2S2_SD,,,,,,,,,,,,,,, +PortD,PD5,USART2_TX,,,,,,,,,,,,,,,, +PortD,PD6,USART2_RX,,,,,,,,,,,,,,,, +PortD,PD7,USART2_CK,,,,,,,,,,,,,,,, +PortD,PD8,USART3_TX,,,,,,,,,,,,,,,, +PortD,PD9,USART3_RX,,,,,,,,,,,,,,,, +PortD,PD10,USART3_CK,,,,,,,,,,,,,,,, +PortD,PD11,USART3_CTS,,,,,,,,,,,,,,,, +PortD,PD12,USART3_RTS,TSC_G8_IO1,USART8_CK/USART8_RTS,,,,,,,,,,,,,, +PortD,PD13,USART8_TX,TSC_G8_IO2,,,,,,,,,,,,,,, +PortD,PD14,USART8_RX,TSC_G8_IO3,,,,,,,,,,,,,,, +PortD,PD15,CRS_SYNC,TSC_G8_IO4,USART7_CK/USART7_RTS,,,,,,,,,,,,,, +PortE,PE0,TIM16_CH1,EVENTOUT,,,,,,,,,,,,,,, +PortE,PE1,TIM17_CH1,EVENTOUT,,,,,,,,,,,,,,, +PortE,PE2,TIM3_ETR,TSC_G7_IO1,,,,,,,,,,,,,,, +PortE,PE3,TIM3_CH1,TSC_G7_IO2,,,,,,,,,,,,,,, +PortE,PE4,TIM3_CH2,TSC_G7_IO3,,,,,,,,,,,,,,, +PortE,PE5,TIM3_CH3,TSC_G7_IO4,,,,,,,,,,,,,,, +PortE,PE6,TIM3_CH4,,,,,,,,,,,,,,,, +PortE,PE7,TIM1_ETR,USART5_CK/USART5_RTS,,,,,,,,,,,,,,, +PortE,PE8,TIM1_CH1N,USART4_TX,,,,,,,,,,,,,,, +PortE,PE9,TIM1_CH1,USART4_RX,,,,,,,,,,,,,,, +PortE,PE10,TIM1_CH2N,USART5_TX,,,,,,,,,,,,,,, +PortE,PE11,TIM1_CH2,USART5_RX,,,,,,,,,,,,,,, +PortE,PE12,TIM1_CH3N,SPI1_NSS/I2S1_WS,,,,,,,,,,,,,,, +PortE,PE13,TIM1_CH3,SPI1_SCK/I2S1_CK,,,,,,,,,,,,,,, +PortE,PE14,TIM1_CH4,SPI1_MISO/I2S1_MCK,,,,,,,,,,,,,,, +PortE,PE15,TIM1_BKIN,SPI1_MOSI/I2S1_SD,,,,,,,,,,,,,,, +PortF,PF0,CRS_SYNC,I2C1_SDA,,,,,,,,,,,,,,, +PortF,PF1,,I2C1_SCL,,,,,,,,,,,,,,, +PortF,PF2,EVENTOUT,USART7_TX,USART7_CK/USART7_RTS,,,,,,,,,,,,,, +PortF,PF3,EVENTOUT,USART7_RX,USART6_CK/USART6_RTS,,,,,,,,,,,,,, +PortF,PF6,,,,,,,,,,,,,,,,, +PortF,PF9,TIM15_CH1,USART6_TX,,,,,,,,,,,,,,, +PortF,PF10,TIM15_CH2,USART6_RX,,,,,,,,,,,,,,, diff --git a/ports/stm32/boards/stm32f091xc.ld b/ports/stm32/boards/stm32f091xc.ld new file mode 100644 index 0000000000..73b8442957 --- /dev/null +++ b/ports/stm32/boards/stm32f091xc.ld @@ -0,0 +1,26 @@ +/* + GNU linker script for STM32F091xC +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K + FLASH_TEXT (rx) : ORIGIN = 0x08000000, LENGTH = 256K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20006800; /* room for a 6k stack */ diff --git a/ports/stm32/boards/stm32f401_af.csv b/ports/stm32/boards/stm32f401_af.csv index 3b29e13495..1acb8e4313 100644 --- a/ports/stm32/boards/stm32f401_af.csv +++ b/ports/stm32/boards/stm32f401_af.csv @@ -13,13 +13,13 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,OTG_FS_VBUS,,,,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,USART6_TX,,OTG_FS_DM,,,,,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,USART6_RX,,OTG_FS_DP,,,,,EVENTOUT, -PortA,PA13,JTMS_SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK_SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,,,,,,,,,,EVENTOUT,ADC1_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,,,,,,,,,,EVENTOUT,ADC1_IN9 PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, -PortB,PB3,JTDO_SWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,I2C2_SDA,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,I2C2_SDA,,,,,,EVENTOUT, PortB,PB4,JTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,I2C3_SDA,,,,,,EVENTOUT, PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,,,,,,,EVENTOUT, PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,,,,,,EVENTOUT, diff --git a/ports/stm32/boards/stm32f401xd.ld b/ports/stm32/boards/stm32f401xd.ld index 89f6056096..7c0e790185 100644 --- a/ports/stm32/boards/stm32f401xd.ld +++ b/ports/stm32/boards/stm32f401xd.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f401xe.ld b/ports/stm32/boards/stm32f401xe.ld index ae2f899048..e76bbad1c2 100644 --- a/ports/stm32/boards/stm32f401xe.ld +++ b/ports/stm32/boards/stm32f401xe.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f405.ld b/ports/stm32/boards/stm32f405.ld index c6107913f2..0375491f65 100644 --- a/ports/stm32/boards/stm32f405.ld +++ b/ports/stm32/boards/stm32f405.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f405_af.csv b/ports/stm32/boards/stm32f405_af.csv index 81f5e80ed1..e6d8fcc2b5 100644 --- a/ports/stm32/boards/stm32f405_af.csv +++ b/ports/stm32/boards/stm32f405_af.csv @@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT, -PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 diff --git a/ports/stm32/boards/stm32f411.ld b/ports/stm32/boards/stm32f411.ld index 7adfa35c95..9e3e6bc154 100644 --- a/ports/stm32/boards/stm32f411.ld +++ b/ports/stm32/boards/stm32f411.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f411_af.csv b/ports/stm32/boards/stm32f411_af.csv index 29267b1d95..d5b7a61deb 100644 --- a/ports/stm32/boards/stm32f411_af.csv +++ b/ports/stm32/boards/stm32f411_af.csv @@ -13,13 +13,13 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,USB_FS_VBUS,,SDIO_D2,,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,SPI5_MOSI/I2S5_SD,USART1_RX,,,USB_FS_ID,,,,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,SPI4_MISO,USART1_CTS,USART6_TX,,USB_FS_DM,,,,,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,SPI5_MISO,USART1_RTS,USART6_RX,,USB_FS_DP,,,,,EVENTOUT, -PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART1_TX,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,,,,SPI5_SCK/I2S5_CK,,,,,,,,,EVENTOUT,ADC1_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,,,,SPI5_NSS/I2S5_WS,,,,,,,,,EVENTOUT,ADC1_IN9 PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT, -PortB,PB3,JTDO-SWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,USART1_RX,,I2C2_SDA,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,USART1_RX,,I2C2_SDA,,,,,,EVENTOUT, PortB,PB4,JTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,I2C3_SDA,,,SDIO_D0,,,EVENTOUT, PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,,,,SDIO_D3,,,EVENTOUT, PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,,,,,,EVENTOUT, diff --git a/ports/stm32/boards/stm32f429.ld b/ports/stm32/boards/stm32f429.ld index a0931684d2..d80f7f5416 100644 --- a/ports/stm32/boards/stm32f429.ld +++ b/ports/stm32/boards/stm32f429.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f429_af.csv b/ports/stm32/boards/stm32f429_af.csv index 2e501ade0b..4ee8edd703 100644 --- a/ports/stm32/boards/stm32f429_af.csv +++ b/ports/stm32/boards/stm32f429_af.csv @@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, -PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld index a76a0ebc79..16c606eccc 100644 --- a/ports/stm32/boards/stm32f439.ld +++ b/ports/stm32/boards/stm32f439.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; /* top end of the stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f439_af.csv b/ports/stm32/boards/stm32f439_af.csv index 5d5c3e72d6..4fc1f1116c 100644 --- a/ports/stm32/boards/stm32f439_af.csv +++ b/ports/stm32/boards/stm32f439_af.csv @@ -13,8 +13,8 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT, PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, -PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 @@ -64,15 +64,15 @@ PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,,,,FMC_A17,,,EVENTOUT, PortD,PD13,,,TIM4_CH2,,,,,,,,,,FMC_A18,,,EVENTOUT, PortD,PD14,,,TIM4_CH3,,,,,,,,,,FMC_D0,,,EVENTOUT, PortD,PD15,,,TIM4_CH4,,,,,,,,,,FMC_D1,,,EVENTOUT, -PortE,PE0,,,TIM4_ETR,,,,,,UART8_Rx,,,,FMC_NBL0,DCMI_D2,,EVENTOUT, -PortE,PE1,,,,,,,,,UART8_Tx,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,,,,,,UART8_RX,,,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,,,,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, PortE,PE6,TRACED3,,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, -PortE,PE7,,TIM1_ETR,,,,,,,UART7_Rx,,,,FMC_D4,,,EVENTOUT, -PortE,PE8,,TIM1_CH1N,,,,,,,UART7_Tx,,,,FMC_D5,,,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,,,FMC_D5,,,EVENTOUT, PortE,PE9,,TIM1_CH1,,,,,,,,,,,FMC_D6,,,EVENTOUT, PortE,PE10,,TIM1_CH2N,,,,,,,,,,,FMC_D7,,,EVENTOUT, PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,SPI3_NSS,,,,,,FMC_D8,,LCD_G3,EVENTOUT, @@ -86,8 +86,8 @@ PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 -PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_Rx,,,,FMC_NIORD,,,EVENTOUT,ADC3_IN4 -PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_Tx,,,,FMC_NREG,,,EVENTOUT,ADC3_IN5 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,,,,FMC_NIORD,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,,,,FMC_NREG,,,EVENTOUT,ADC3_IN5 PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,,TIM13_CH1,,,FMC_NIOWR,,,EVENTOUT,ADC3_IN6 PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,,TIM14_CH1,,,FMC_CD,,,EVENTOUT,ADC3_IN7 PortF,PF10,,,,,,,,,,,,,FMC_INTR,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8 diff --git a/ports/stm32/boards/stm32f4xx_prefix.c b/ports/stm32/boards/stm32f4xx_prefix.c index f4ffdab68e..3bcd6e6410 100644 --- a/ports/stm32/boards/stm32f4xx_prefix.c +++ b/ports/stm32/boards/stm32f4xx_prefix.c @@ -14,7 +14,7 @@ .fn = AF_FN_ ## af_fn, \ .unit = (af_unit), \ .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ - .af_fn = (af_ptr) \ + .reg = (af_ptr) \ } #define PIN(p_port, p_pin, p_af, p_adc_num, p_adc_channel) \ diff --git a/ports/stm32/boards/stm32f722.ld b/ports/stm32/boards/stm32f722.ld new file mode 100644 index 0000000000..f2a1d85117 --- /dev/null +++ b/ports/stm32/boards/stm32f722.ld @@ -0,0 +1,27 @@ +/* + GNU linker script for STM32F722, STM32F723, STM32F732, STM32F733 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sectors 0,1 */ + FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 480K /* sectors 2-7 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K /* DTCM+SRAM1+SRAM2 */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x20038000; /* tunable */ diff --git a/ports/stm32/boards/stm32f722_af.csv b/ports/stm32/boards/stm32f722_af.csv new file mode 100644 index 0000000000..24500f5057 --- /dev/null +++ b/ports/stm32/boards/stm32f722_af.csv @@ -0,0 +1,146 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1,I2C1/2/3/USART1,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5,SPI2/I2S2/SPI3/I2S3/SPI3/I2S3/SAI1/UART4,SPI2/I2S2/SPI3/I2S3/USART1/2/3/UART5,SAI2/USART6/UART4/5/7/8/OTG1_FS,CAN1/TIM12/13/14/QUADSPI/FMC/OTG2_HS,SAI2/QUADSPI/SDMMC2/OTG2_HS/OTG1_FS,SDMMC2,UART7/FMC/SDMMC1/OTG2_FS,,,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,,,,,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,,,,,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,,,,,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,,,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,,,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,,FMC_SDNWE,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,,,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,,,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,UART4_CTS,,OTG_HS_ULPI_D1,,,,,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,,,,,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,SDMMC2_D2,,,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,SDMMC2_D3,,,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,,OTG_HS_ULPI_D7,,FMC_SDCKE1,,,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,QUADSPI_BK1_NCS,,FMC_SDNE1,,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,,,EVENTOUT, +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,SDMMC2_D4,,SDMMC1_D4,,,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,SDMMC2_D5,,SDMMC1_D5,,,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,,,,,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,,,,,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,,OTG_HS_ULPI_D5,,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,,OTG_HS_ULPI_D6,,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,,USART3_RTS,,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,,,,,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,,EVENTOUT,ADC123_IN10 +PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,,,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,,,SPI2_MISO,,,,,OTG_HS_ULPI_DIR,,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,,,I2S1_MCK,,,,,,,FMC_SDNE0,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,,,,,,,,,,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,SDMMC2_D6,,SDMMC1_D6,,,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,SDMMC2_D7,,SDMMC1_D7,,,EVENTOUT, +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,,,,SDMMC1_D0,,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,,,EVENTOUT, +PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,,,EVENTOUT, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT, +PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,,,EVENTOUT, +PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT, +PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,SDMMC2_CK,FMC_NWAIT,,,EVENTOUT, +PortD,PD7,,,,,,,,USART2_CK,,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,,,,,USART3_TX,,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,,EVENTOUT, +PortD,PD11,,,,,,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,,,EVENTOUT, +PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,,,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,,,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,,,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8,,,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9,,,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10,,,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,,,,,,,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT,,,EVENTOUT, +PortG,PG8,,,,,,,,,USART6_RTS,,,,FMC_SDCLK,,,EVENTOUT, +PortG,PG9,,,,,,,,,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,,,EVENTOUT, +PortG,PG10,,,,,,,,,,,SAI2_SD_B,SDMMC2_D1,FMC_NE3,,,EVENTOUT, +PortG,PG11,,,,,,,,,,,SDMMC2_D2,,,,,EVENTOUT, +PortG,PG12,,,,LPTIM1_IN1,,,,,USART6_RTS,,,SDMMC2_D3,FMC_NE4,,,EVENTOUT, +PortG,PG13,TRACED0,,,LPTIM1_OUT,,,,,USART6_CTS,,,,FMC_A24,,,EVENTOUT, +PortG,PG14,TRACED1,,,LPTIM1_ETR,,,,,USART6_TX,QUADSPI_BK2_IO3,,,FMC_A25,,,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,,FMC_SDCKE0,,,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,,FMC_SDNE0,,,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,,FMC_SDNE1,,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,,FMC_SDCKE1,,,EVENTOUT, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,,,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,,,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,,,,,,,,,FMC_D18,,,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,,,,,,,,,FMC_D19,,,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,,,,,,,,,FMC_D20,,,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,,,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,,,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,,,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,,,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,,,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,,,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,,,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,,,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,,,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,,EVENTOUT, +PortI,PI10,,,,,,,,,,,,,FMC_D31,,,EVENTOUT, +PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI15,,,,,,,,,,,,,,,,EVENTOUT, diff --git a/ports/stm32/boards/stm32f746.ld b/ports/stm32/boards/stm32f746.ld index ce5e85bb6d..b5864453dd 100644 --- a/ports/stm32/boards/stm32f746.ld +++ b/ports/stm32/boards/stm32f746.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f746_af.csv b/ports/stm32/boards/stm32f746_af.csv index eabc9ab3ba..8069edc7b9 100644 --- a/ports/stm32/boards/stm32f746_af.csv +++ b/ports/stm32/boards/stm32f746_af.csv @@ -5,7 +5,7 @@ PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B, PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,,,LCD_R1,EVENTOUT PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT -PortA,PA5,,TIM2_CH1/TIM2_ETR,TIM8_CH1N,SPI1_SCK/I2S1_CK,,,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT @@ -13,16 +13,16 @@ PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,,EVENTO PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT -PortA,PA13,JTMS,SWDIO,,,,,,,,,,,,,,EVENTOUT -PortA,PA14,JTCK,SWCLK,,,,,,,,,,,,,,EVENTOUT -PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMICE,CSPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT -PortB,PB0,,TIM1_CH2N,TIM3_CH3T,IM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT -PortB,PB1,,TIM1_CH3N,TIM3_CH4T,IM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,,,,,,EVENTOUT PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT -PortB,PB6,,,TIM4_CH1,HDMICEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT +PortB,PB6,,,TIM4_CH1,HDMI_CEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT @@ -168,4 +168,3 @@ PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT - diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld index 225abd810f..c05fd8021b 100644 --- a/ports/stm32/boards/stm32f767.ld +++ b/ports/stm32/boards/stm32f767.ld @@ -7,6 +7,7 @@ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0, 32K */ + FLASH_APP (rx) : ORIGIN = 0x08008000, LENGTH = 2016K /* sectors 1-11 3x32K 1*128K 7*256K */ FLASH_FS (r) : ORIGIN = 0x08008000, LENGTH = 96K /* sectors 1, 2, 3 (32K each) */ FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 896K /* sectors 4-7 1*128Kib 3*256KiB = 896K */ DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ @@ -22,9 +23,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f767_af.csv b/ports/stm32/boards/stm32f767_af.csv index 1708dfcca4..0c8069ec26 100644 --- a/ports/stm32/boards/stm32f767_af.csv +++ b/ports/stm32/boards/stm32f767_af.csv @@ -1,170 +1,170 @@ -Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15 -,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/CEC,I2C1/2/3/4/CEC,SPI1/2/3/4/5/6,SPI3/SAI1,SPI2/3/USART1/2/3/UART5/SPDIFRX,SAI2/USART6/UART4/5/7/8/SPDIFRX,CAN1/2/TIM12/13/14/QUADSPI/LCD,SAI2/QUADSPI/SDMMC2/OTG2_HS/OTG1_FS,SDMMC2/ETH,FMC/SDMMC1/OTG2_FS,DCMI,LCD,SYS -PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT -PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT -PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,,,LCD_R1,EVENTOUT -PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT -PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT -PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT -PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCLK,LCD_G2,EVENTOUT -PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT -PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,LCD_R6,EVENTOUT -PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,,EVENTOUT -PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,,,DCMI_D1,,EVENTOUT -PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT -PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT -PortA,PA13,JTMS,SWDIO,,,,,,,,,,,,,,EVENTOUT -PortA,PA14,JTCK,SWCLK,,,,,,,,,,,,,,EVENTOUT -PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMICEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT -PortB,PB0,,TIM1_CH2N,TIM3_CH3T,TIM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT -PortB,PB1,,TIM1_CH3N,TIM3_CH4T,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT -PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT -PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,SDMMC2_D2,,,,,EVENTOUT -PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,SDMMC2_D3,,,,,EVENTOUT -PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,,EVENTOUT -PortB,PB6,,,TIM4_CH1,HDMICEC,I2C1_SCL,,,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,,FMC_SDNE1,DCMI_D5,,EVENTOUT -PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FMC_NL,DCMI_VSYNC,,EVENTOUT -PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT -PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,SDMMC2_D5,,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT -PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT -PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT -PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT -PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT -PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,,USART3_RTS,,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT -PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT -PortC,PC0,,,,,,,,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT -PortC,PC1,TRACED0,,,,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,,ETH_MDC,,,,EVENTOUT -PortC,PC2,,,,,,SPI2_MISO,,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT -PortC,PC3,,,,,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT -PortC,PC4,,,,,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT -PortC,PC5,,,,,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT -PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT -PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT -PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,,,,SDMMC1_D0,DCMI_D2,,EVENTOUT -PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S2_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,DCMI_D3,,EVENTOUT -PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT -PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT -PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT -PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT -PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT -PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT -PortD,PD0,,,,,,,,,,CAN1_RX,,,FMC_D2,,,EVENTOUT -PortD,PD1,,,,,,,,,,CAN1_TX,,,FMC_D3,,,EVENTOUT -PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT -PortD,PD3,,,,,,SPI2_SCK/I2S2_CK,,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT -PortD,PD4,,,,,,,,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT -PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT -PortD,PD6,,,,,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT -PortD,PD7,,,,,,,,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT -PortD,PD8,,,,,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT -PortD,PD9,,,,,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT -PortD,PD10,,,,,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT -PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT -PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT -PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT -PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT -PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT -PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT -PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT -PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT -PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT -PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT -PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT -PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT -PortE,PE7,,TIM1_ETR,,,,,,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT -PortE,PE8,,TIM1_CH1N,,,,,,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT -PortE,PE9,,TIM1_CH1,,,,,,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT -PortE,PE10,,TIM1_CH2N,,,,,,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT -PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT -PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT -PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT -PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT -PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT -PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT -PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT -PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT -PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT -PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT -PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT -PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT -PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT -PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT -PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT -PortF,PF10,,,,,,,,,,,,,,DCMI_D11,LCD_DE,EVENTOUT -PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT -PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT -PortF,PF13,,,,,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT -PortF,PF14,,,,,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT -PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT -PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT -PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT -PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT -PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT -PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT -PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT -PortG,PG6,,,,,,,,,,,,,,DCMI_D12,LCD_R7,EVENTOUT -PortG,PG7,,,,,,,,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT -PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,,EVENTOUT -PortG,PG9,,,,,,,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT -PortG,PG10,,,,,,,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT -PortG,PG11,,,,,,,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT -PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT -PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT -PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT -PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT -PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT -PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT -PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT -PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT -PortH,PH4,,,,,I2C2_SCL,,,,,,OTG_HS_ULPI_NXT,,,,,EVENTOUT -PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT -PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT -PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT -PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT -PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT -PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT -PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT -PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT -PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT -PortH,PH14,,,,TIM8_CH2N,,,,,,,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT -PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT -PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT -PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT -PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT -PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT -PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT -PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT -PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT -PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT -PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT -PortI,PI9,,,,,,,,,,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT -PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT -PortI,PI11,,,,,,,,,,,OTG_HS_ULPI_DIR,,,,,EVENTOUT -PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT -PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT -PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT -PortI,PI15,,,,,,,,,,,,,,,LCD_R0,EVENTOUT -PortJ,PJ0,,,,,,,,,,,,,,,LCD_R1,EVENTOUT -PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT -PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT -PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT -PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT -PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT -PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT -PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT -PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT -PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT -PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT -PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT -PortJ,PJ12,,,,,,,,,,,,,,,LCD_B0,EVENTOUT -PortJ,PJ13,,,,,,,,,,,,,,,LCD_B1,EVENTOUT -PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT -PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT -PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT -PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT -PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT -PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT -PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT -PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT -PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT -PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,I2C4/UART5/TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/DFSDM1/CEC,I2C1/2/3/4/USART1/CEC,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5/6,SPI2/I2S2/SPI3/I2S3/SAI1/I2C4/UART4/DFSDM1,SPI2/I2S2/SPI3/I2S3/SPI6/USART1/2/3/UART5/DFSDM1/SPDIF,SPI6/SAI2/USART6/UART4/5/7/8/OTG_FS/SPDIF,CAN1/2/TIM12/13/14/QUADSPI/FMC/LCD,SAI2/QUADSPI/SDMMC2/DFSDM1/OTG2_HS/OTG1_FS/LCD,I2C4/CAN3/SDMMC2/ETH,UART7/FMC/SDMMC1/MDIOS/OTG2_FS,DCMI/LCD/DSI,LCD,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,SPI6_MISO,TIM13_CH1,,,MDIOS_MDC,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,CAN3_RX,UART7_RX,LCD_B3,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,LCD_R5,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,LCD_B4,OTG_FS_ID,,MDIOS_MDIO,DCMI_D1,LCD_B1,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,CAN3_TX,UART7_TX,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM1_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATAIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,DFSDM1_CKIN1,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,,SDMMC2_D2,CAN3_RX,UART7_RX,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,SPI6_MISO,,SDMMC2_D3,CAN3_TX,UART7_TX,,,EVENTOUT, +PortB,PB5,,UART5_RX,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT, +PortB,PB6,,UART5_TX,TIM4_CH1,HDMI_CEC,I2C1_SCL,,DFSDM1_DATAIN5,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,I2C4_SCL,FMC_SDNE1,DCMI_D5,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,DFSDM1_CKIN5,USART1_RX,,,,I2C4_SDA,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,I2C4_SCL,TIM4_CH3,TIM10_CH1,I2C1_SCL,,DFSDM1_CKIN7,UART5_RX,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,I2C4_SDA,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN7,UART5_TX,,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DSI_TE,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN1,USART3_CK,UART5_RX,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,DFSDM1_CKIN1,USART3_CTS,UART5_TX,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,USART1_TX,SPI2_MISO,DFSDM1_DATAIN2,USART3_RTS,UART4_RTS,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SD,DFSDM1_CKIN2,,UART4_CTS,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATAIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT,ADC123_IN10 +PortC,PC1,TRACED0,,,DFSDM1_DATAIN0,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,DFSDM1_CKIN4,ETH_MDC,MDIOS_MDC,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,DFSDM1_CKIN1,,SPI2_MISO,DFSDM1_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,DFSDM1_DATAIN1,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,DFSDM1_DATAIN2,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,DFSDM1_CKIN3,USART6_TX,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,DFSDM1_DATAIN3,USART6_RX,FMC_NE1,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,FMC_NE2/FMC_NCE,,,SDMMC1_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,LCD_G3,,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT, +PortC,PC10,,,,DFSDM1_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,,DFSDM1_DATAIN5,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,DFSDM1_CKIN6,,,DFSDM1_DATAIN7,,UART4_RX,CAN1_RX,,,FMC_D2,,,EVENTOUT, +PortD,PD1,,,,DFSDM1_DATAIN6,,,DFSDM1_CKIN7,,UART4_TX,CAN1_TX,,,FMC_D3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,DFSDM1_CKOUT,,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN0,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,,,,,DFSDM1_CKIN0,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,DFSDM1_CKIN4,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,DFSDM1_DATAIN1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,DFSDM1_DATAIN4,,SPI1_MOSI/I2S1_SD,DFSDM1_CKIN1,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,DFSDM1_DATAIN3,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,DFSDM1_CKOUT,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,DFSDM1_DATAIN3,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,DFSDM1_CKIN3,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATAIN2,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATAIN4,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,DFSDM1_CKIN4,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,DFSDM1_DATAIN5,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,DFSDM1_CKIN5,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATAIN6,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT, +PortG,PG9,,,,,,SPI1_MISO,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,,,,SPI1_SCK/I2S1_CK,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,DSI_TE,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, diff --git a/ports/stm32/boards/stm32f769.ld b/ports/stm32/boards/stm32f769.ld index c4cabe7a4d..d6da439435 100644 --- a/ports/stm32/boards/stm32f769.ld +++ b/ports/stm32/boards/stm32f769.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld new file mode 100644 index 0000000000..77bbfacb10 --- /dev/null +++ b/ports/stm32/boards/stm32h743.ld @@ -0,0 +1,29 @@ +/* + GNU linker script for STM32H743 +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* sector 0, 128K */ + FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* sector 1, 128K */ + FLASH_TEXT (rx) : ORIGIN = 0x08040000, LENGTH = 1792K /* sectors 6*128 + 8*128 */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ + RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM */ +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2407C000; /* tunable */ diff --git a/ports/stm32/boards/stm32h743_af.csv b/ports/stm32/boards/stm32h743_af.csv new file mode 100644 index 0000000000..d008ba68b6 --- /dev/null +++ b/ports/stm32/boards/stm32h743_af.csv @@ -0,0 +1,170 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2/16/17/LPTIM1/HRTIM1,SAI1/TIM3/4/5/12/HRTIM1,LPUART/TIM8/LPTIM2/3/4/5/HRTIM1/DFSDM,I2C1/2/3/4/USART1/TIM15/LPTIM2/DFSDM/CEC,SPI1/2/3/4/5/6/CEC,SPI2/3/SAI1/3/I2C4/UART4/DFSDM,SPI2/3/6/USART1/2/3/6/UART7/SDMMC1,SPI6/SAI2/4/UART4/5/8/LPUART/SDMMC1/SPDIFRX,SAI4/FDCAN1/2/TIM13/14/QUADSPI/FMC/SDMMC2/LCD/SPDIFRX,SAI2/4/TIM8/QUADSPI/SDMMC2/OTG1_HS/OTG2_FS/LCD,I2C4/UART7/SWPMI1/TIM1/8/DFSDM/SDMMC2/MDIOS/ETH,TIM1/8/FMC/SDMMC1/MDIOS/OTG1_FS/LCD,TIM1/DCMI/LCD/COMP,UART5/LCD,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,,,USART2_CTS/USART2_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT, +PortA,PA1,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT, +PortA,PA2,,TIM2_CH3,TIM5_CH3,LPTIM4_OUT,TIM15_CH1,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT, +PortA,PA3,,TIM2_CH4,TIM5_CH4,LPTIM5_OUT,TIM15_CH2,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT, +PortA,PA4,,,TIM5_ETR,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT, +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT, +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO/I2S1_SDI,,,SPI6_MISO,TIM13_CH1,TIM8_BKIN_COMP12,MDIOS_MDC,TIM1_BKIN_COMP12,DCMI_PIXCLK,LCD_G2,EVENTOUT, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SDO,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT, +PortA,PA8,MCO1,TIM1_CH1,HRTIM_CHB2,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,UART7_RX,TIM8_BKIN2_COMP12,LCD_B3,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,HRTIM_CHC1,LPUART1_TX,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,CAN1_RXFD,,ETH_TX_ER,,DCMI_D0,LCD_R5,EVENTOUT, +PortA,PA10,,TIM1_CH3,HRTIM_CHC2,LPUART1_RX,,,,USART1_RX,,CAN1_TXFD,OTG_FS_ID,MDIOS_MDIO,LCD_B4,DCMI_D1,LCD_B1,EVENTOUT, +PortA,PA11,,TIM1_CH4,HRTIM_CHD1,LPUART1_CTS,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS/USART1_NSS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,HRTIM_CHD2,LPUART1_RTS,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,HRTIM_FLT1,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,UART7_TX,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT, +PortB,PB2,,,SAI1_D1,,DFSDM_CKIN1,,SAI1_SD_A,SPI3_MOSI/I2S3_SDO,SAI4_SD_A,QUADSPI_CLK,SAI4_D1,ETH_TX_ER,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,HRTIM_FLT4,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,SDMMC2_D2,,UART7_RX,,,,EVENTOUT, +PortB,PB4,NJTRST,TIM16_BKIN,TIM3_CH1,HRTIM_EEV6,,SPI1_MISO/I2S1_SDI,SPI3_MISO/I2S3_SDI,SPI2_NSS/I2S2_WS,SPI6_MISO,SDMMC2_D3,,UART7_TX,,,,EVENTOUT, +PortB,PB5,,TIM17_BKIN,TIM3_CH2,HRTIM_EEV7,I2C1_SMBA,SPI1_MOSI/I2S1_SDO,I2C4_SMBA,SPI3_MOSI/I2S3_SDO,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,UART5_RX,EVENTOUT, +PortB,PB6,,TIM16_CH1N,TIM4_CH1,HRTIM_EEV8,I2C1_SCL,HDMI_CEC,I2C4_SCL,USART1_TX,LPUART1_TX,CAN2_TX,QUADSPI_BK1_NCS,DFSDM_DATIN5,FMC_SDNE1,DCMI_D5,UART5_TX,EVENTOUT, +PortB,PB7,,TIM17_CH1N,TIM4_CH2,HRTIM_EEV9,I2C1_SDA,,I2C4_SDA,USART1_RX,LPUART1_RX,CAN2_TXFD,,DFSDM_CKIN5,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,TIM16_CH1,TIM4_CH3,DFSDM_CKIN7,I2C1_SCL,,I2C4_SCL,SDMMC1_CKIN,UART4_RX,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,TIM17_CH1,TIM4_CH4,DFSDM_DATIN7,I2C1_SDA,SPI2_NSS/I2S2_WS,I2C4_SDA,SDMMC1_CDIR,UART4_TX,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,HRTIM_SCOUT,LPTIM2_IN1,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM_DATIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,HRTIM_SCIN,LPTIM2_ETR,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM_DATIN1,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,TIM1_BKIN_COMP12,UART5_RX,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,LPTIM2_OUT,,SPI2_SCK/I2S2_CK,DFSDM_CKIN1,USART3_CTS/USART3_NSS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,UART5_TX,EVENTOUT, +PortB,PB14,,TIM1_CH2N,TIM12_CH1,TIM8_CH2N,USART1_TX,SPI2_MISO/I2S2_SDI,DFSDM_DATIN2,USART3_RTS,UART4_RTS,SDMMC2_D0,,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,TIM12_CH2,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SDO,DFSDM_CKIN2,,UART4_CTS,SDMMC2_D1,,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,DFSDM_CKIN0,,,DFSDM_DATIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT, +PortC,PC1,TRACED0,,SAI1_D1,DFSDM_DATIN0,DFSDM_CKIN4,SPI2_MOSI/I2S2_SDO,SAI1_SD_A,,SAI4_SD_A,SDMMC2_CK,SAI4_D1,ETH_MDC,MDIOS_MDC,,,EVENTOUT, +PortC,PC2,,,,DFSDM_CKIN1,,SPI2_MISO/I2S2_SDI,DFSDM_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT, +PortC,PC3,,,,DFSDM_DATIN1,,SPI2_MOSI/I2S2_SDO,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT, +PortC,PC4,,,,DFSDM_CKIN2,,I2S1_MCK,,,,SPDIFRX_IN2,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT, +PortC,PC5,,,SAI1_D3,DFSDM_DATIN2,,,,,,SPDIFRX_IN3,SAI4_D3,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,COMP_1_OUT,,EVENTOUT, +PortC,PC6,,HRTIM_CHA1,TIM3_CH1,TIM8_CH1,DFSDM_CKIN3,I2S2_MCK,,USART6_TX,SDMMC1_D0DIR,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,TRGIO,HRTIM_CHA2,TIM3_CH2,TIM8_CH2,DFSDM_DATIN3,,I2S3_MCK,USART6_RX,SDMMC1_D123DIR,FMC_NE1,SDMMC2_D7,SWPMI_TX,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,TRACED1,HRTIM_CHB1,TIM3_CH3,TIM8_CH3,,,,USART6_CK,UART5_RTS,FMC_NE2/FMC_NCE,,SWPMI_RX,SDMMC1_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,UART5_CTS,QUADSPI_BK1_IO0,LCD_G3,SWPMI_SUSPEND,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT, +PortC,PC10,,,HRTIM_EEV1,DFSDM_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,HRTIM_FLT2,DFSDM_DATIN5,,,SPI3_MISO/I2S3_SDI,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,TRACED3,,HRTIM_EEV2,,,,SPI3_MOSI/I2S3_SDO,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,DFSDM_CKIN6,,,SAI3_SCK_A,,UART4_RX,CAN1_RX,,,FMC_D2/FMC_DA2,,,EVENTOUT, +PortD,PD1,,,,DFSDM_DATIN6,,,SAI3_SD_A,,UART4_TX,CAN1_TX,,,FMC_D3/FMC_DA3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,DFSDM_CKOUT,,SPI2_SCK/I2S2_CK,,USART2_CTS/USART2_NSS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,HRTIM_FLT3,,,,SAI3_FS_A,USART2_RTS,,CAN1_RXFD,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,HRTIM_EEV3,,,,,USART2_TX,,CAN1_TXFD,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,SAI1_D1,DFSDM_CKIN4,DFSDM_DATIN1,SPI3_MOSI/I2S3_SDO,SAI1_SD_A,USART2_RX,SAI4_SD_A,CAN2_RXFD,SAI4_D1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,DFSDM_DATIN4,,SPI1_MOSI/I2S1_SDO,DFSDM_CKIN1,USART2_CK,,SPDIFRX_IN0,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,DFSDM_CKIN3,,,SAI3_SCK_B,USART3_TX,,SPDIFRX_IN1,,,FMC_D13/FMC_DA13,,,EVENTOUT, +PortD,PD9,,,,DFSDM_DATIN3,,,SAI3_SD_B,USART3_RX,,CAN2_RXFD,,,FMC_D14/FMC_DA14,,,EVENTOUT, +PortD,PD10,,,,DFSDM_CKOUT,,,SAI3_FS_B,USART3_CK,,CAN2_TXFD,,,FMC_D15/FMC_DA15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,LPTIM2_IN2,I2C4_SMBA,,,USART3_CTS/USART3_NSS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16,,,EVENTOUT, +PortD,PD12,,LPTIM1_IN1,TIM4_CH1,LPTIM2_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17,,,EVENTOUT, +PortD,PD13,,LPTIM1_OUT,TIM4_CH2,,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,SAI3_MCLK_B,,UART8_CTS,,,,FMC_D0/FMC_DA0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,SAI3_MCLK_A,,UART8_RTS,,,,FMC_D1/FMC_DA1,,,EVENTOUT, +PortE,PE0,,LPTIM1_ETR,TIM4_ETR,HRTIM_SCIN,LPTIM2_ETR,,,,UART8_RX,CAN1_RXFD,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,LPTIM1_IN2,,HRTIM_SCOUT,,,,,UART8_TX,CAN1_TXFD,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,SAI1_CK1,,,SPI4_SCK,SAI1_MCLK_A,,SAI4_MCLK_A,QUADSPI_BK1_IO2,SAI4_CK1,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,TIM15_BKIN,,SAI1_SD_B,,SAI4_SD_B,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,SAI1_D2,DFSDM_DATIN3,TIM15_CH1N,SPI4_NSS,SAI1_FS_A,,SAI4_FS_A,,SAI4_D2,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,SAI1_CK2,DFSDM_CKIN3,TIM15_CH1,SPI4_MISO,SAI1_SCK_A,,SAI4_SCK_A,,SAI4_CK2,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,SAI1_D1,,TIM15_CH2,SPI4_MOSI,SAI1_SD_A,,SAI4_SD_A,SAI4_D1,SAI2_MCK_B,TIM1_BKIN2_COMP12,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,DFSDM_DATIN2,,,,UART7_RX,,,QUADSPI_BK2_IO0,,FMC_D4/FMC_DA4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,DFSDM_CKIN2,,,,UART7_TX,,,QUADSPI_BK2_IO1,,FMC_D5/FMC_DA5,COMP_2_OUT,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,DFSDM_CKOUT,,,,UART7_RTS,,,QUADSPI_BK2_IO2,,FMC_D6/FMC_DA6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,DFSDM_DATIN4,,,,UART7_CTS,,,QUADSPI_BK2_IO3,,FMC_D7/FMC_DA7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,DFSDM_CKIN4,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8/FMC_DA8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,DFSDM_DATIN5,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9/FMC_DA9,COMP_1_OUT,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,DFSDM_CKIN5,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10/FMC_DA10,COMP_2_OUT,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11/FMC_DA11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,HDMI__TIM1_BKIN,,,,,,,FMC_D12/FMC_DA12,TIM1_BKIN_COMP12,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT, +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT, +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT, +PortF,PF6,,TIM16_CH1,,,,SPI5_NSS,SAI1_SD_B,UART7_RX,SAI4_SD_B,QUADSPI_BK1_IO3,,,,,,EVENTOUT, +PortF,PF7,,TIM17_CH1,,,,SPI5_SCK,SAI1_MCLK_B,UART7_TX,SAI4_MCLK_B,QUADSPI_BK1_IO2,,,,,,EVENTOUT, +PortF,PF8,,TIM16_CH1N,,,,SPI5_MISO,SAI1_SCK_B,UART7_RTS,SAI4_SCK_B,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT, +PortF,PF9,,TIM17_CH1N,,,,SPI5_MOSI,SAI1_FS_B,UART7_CTS,SAI4_FS_B,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT, +PortF,PF10,,TIM16_BKIN,SAI1_D3,,,,,,,QUADSPI_CLK,SAI4_D3,,,DCMI_D11,LCD_DE,EVENTOUT, +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,DFSDM_DATIN6,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,DFSDM_CKIN6,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,TIM8_BKIN,,,,,,,,TIM8_BKIN_COMP12,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,TIM8_BKIN2,,,,,,,,TIM8_BKIN2_COMP12,FMC_A13,,,EVENTOUT, +PortG,PG4,,TIM1_BKIN2,,,,,,,,,,TIM1_BKIN2_COMP12,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,TIM1_ETR,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,TIM17_BKIN,HRTIM_CHE1,,,,,,,,QUADSPI_BK1_NCS,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,HRTIM_CHE2,,,,SAI1_MCLK_A,USART6_CK,,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,TIM8_ETR,,SPI6_NSS,,USART6_RTS,SPDIFRX_IN2,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT, +PortG,PG9,,,,,,SPI1_MISO/I2S1_SDI,,USART6_RX,SPDIFRX_IN3,QUADSPI_BK2_IO2,SAI2_FS_B,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,HRTIM_FLT5,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,HRTIM_EEV4,,,SPI1_SCK/I2S1_CK,,,SPDIFRX_IN0,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,LPTIM1_IN1,HRTIM_EEV5,,,SPI6_MISO,,USART6_RTS,SPDIFRX_IN1,LCD_B4,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,TRACED0,LPTIM1_OUT,HRTIM_EEV10,,,SPI6_SCK,,USART6_CTS/USART6_NSS,,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG14,TRACED1,LPTIM1_ETR,,,,SPI6_MOSI,,USART6_TX,,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT, +PortG,PG15,,,,,,,,USART6_CTS/USART6_NSS,,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,LPTIM1_IN2,,,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,TIM12_CH1,,I2C2_SMBA,SPI5_SCK,,,,,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT, +PortH,PH8,,,TIM5_ETR,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,TIM12_CH2,,I2C3_SMBA,,,,,,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,CAN1_TXFD,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,CAN1_RXFD,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,TIM8_BKIN2_COMP12,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO/I2S2_SDI,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SDO,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,TIM8_BKIN_COMP12,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,CAN1_RXFD,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,ETH_TX_ER,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,TIM8_CH2,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,TRGIN,,,TIM8_CH2N,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,TIM1_CH3N,,TIM8_CH1,,,,,UART8_TX,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,TIM1_CH3,,TIM8_CH1N,,,,,UART8_RX,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,TIM1_CH2N,,TIM8_CH2,,SPI5_MOSI,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,TIM1_CH2,,TIM8_CH2N,,SPI5_MISO,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,TRGOUT,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,LCD_B4,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,TIM1_CH1N,,TIM8_CH3,,SPI5_SCK,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,TIM1_CH1,,TIM8_CH3N,,SPI5_NSS,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,TIM1_BKIN,,TIM8_BKIN,,,,,,,TIM8_BKIN_COMP12,TIM1_BKIN_COMP12,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, diff --git a/ports/stm32/boards/stm32l476_af.csv b/ports/stm32/boards/stm32l476_af.csv index d67c33880f..01db895725 100644 --- a/ports/stm32/boards/stm32l476_af.csv +++ b/ports/stm32/boards/stm32l476_af.csv @@ -1,7 +1,7 @@ Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,, ,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5, -PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6, +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS/USART2_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6, PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,,,,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7, PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,,,,LCD_SEG2,,,TIM15_CH2,EVENTOUT,ADC12_IN8, PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9, @@ -12,15 +12,15 @@ PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,,,LPTIM2_OUT,EVENTOU PortA,PA9,,TIM1_CH2,,,,,,USART1_TX,,,,LCD_COM1,,,TIM15_BKIN,EVENTOUT,, PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,,TIM17_BKIN,EVENTOUT,, PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,, -PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,, -PortA,PA13,JTMS-SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,, -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT,, -PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS/USART1_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,, +PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT,, +PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS/UART4_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,, PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,,,EVENTOUT,ADC12_IN15, -PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS/USART3_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM_CKIN0,,,,,,,,,EVENTOUT,,COMP1_INP -PortB,PB3,JTDO-TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM -PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS/USART1_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS/UART5_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP PortB,PB5,,LPTIM1_IN1,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,, PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,,DFSDM_DATIN5,USART1_TX,,TSC_G2_IO3,,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,,DFSDM_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM @@ -28,7 +28,7 @@ PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM_DATIN6,,,CAN1_RX,,LCD_SEG16,SDMMC1_D4,SAI1 PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM_CKIN6,,,CAN1_TX,,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,, PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK,DFSDM_DATIN7,USART3_TX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,, PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,, -PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,, PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,, PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,, @@ -50,9 +50,9 @@ PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,, PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,, PortD,PD0,,,,,,SPI2_NSS,DFSDM_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,, PortD,PD1,,,,,,SPI2_SCK,DFSDM_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,, -PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,, +PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,, PortD,PD3,,,,,,SPI2_MISO,DFSDM_DATIN0,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT,, -PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS_DE,,,,,FMC_NOE,,,EVENTOUT,, +PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS/USART2_DE,,,,,FMC_NOE,,,EVENTOUT,, PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT,, PortD,PD6,,,,,,,DFSDM_DATIN1,USART2_RX,,,,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,, PortD,PD7,,,,,,,DFSDM_CKIN1,USART2_CK,,,,,FMC_NE1,,,EVENTOUT,, @@ -60,13 +60,13 @@ PortD,PD8,,,,,,,,USART3_TX,,,,LCD_SEG28,FMC_D13,,,EVENTOUT,, PortD,PD9,,,,,,,,USART3_RX,,,,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,, PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,, PortD,PD11,,,,,,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,, -PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,, +PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,, PortD,PD13,,,TIM4_CH2,,,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,, PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,, PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,, PortE,PE0,,,TIM4_ETR,,,,,,,,,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,, PortE,PE1,,,,,,,,,,,,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,, -PortE,PE2,TRACECK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,, +PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,, PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,, PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM_DATIN3,,,TSC_G7_IO3,,,FMC_A20,SAI1_FS_A,,EVENTOUT,, PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM_CKIN3,,,TSC_G7_IO4,,,FMC_A21,SAI1_SCK_A,,EVENTOUT,, @@ -102,13 +102,13 @@ PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,, PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,, PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,, PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,, -PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS_DE,,,,,,,EVENTOUT,, +PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS/LPUART1_DE,,,,,,,EVENTOUT,, PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT3,,,EVENTOUT,, PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,, PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE3/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,, PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,, -PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,, +PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS/USART1_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,, PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,, PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,, PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,,,,,EVENTOUT,, diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld index 11b2972ade..22c4466c66 100644 --- a/ports/stm32/boards/stm32l476xe.ld +++ b/ports/stm32/boards/stm32l476xe.ld @@ -11,6 +11,7 @@ MEMORY FLASH_FS (r) : ORIGIN = 0x08060000, LENGTH = 128K /* sectors 192-255 */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K + FS_CACHE(xrw) : ORIGIN = 0x10007800, LENGTH = 2K } /* produce a link error if there is not this amount of RAM for these sections */ @@ -22,10 +23,9 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ +_ram_fs_cache_start = ORIGIN(FS_CACHE); +_ram_fs_cache_block_size = LENGTH(FS_CACHE); _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld index a94fa27504..40d679ac39 100644 --- a/ports/stm32/boards/stm32l476xg.ld +++ b/ports/stm32/boards/stm32l476xg.ld @@ -11,10 +11,9 @@ MEMORY FLASH_FS (r) : ORIGIN = 0x08080000, LENGTH = 512K /* sectors 256-511 */ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K + FS_CACHE(xrw) : ORIGIN = 0x10007800, LENGTH = 2K } -ENTRY(Reset_Handler) - /* produce a link error if there is not this amount of RAM for these sections */ _minimum_stack_size = 2K; _minimum_heap_size = 16K; @@ -24,10 +23,9 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ +_ram_fs_cache_start = ORIGIN(FS_CACHE); +_ram_fs_cache_block_size = LENGTH(FS_CACHE); _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); _heap_start = _ebss; /* heap starts just after statically allocated memory */ diff --git a/ports/stm32/boards/stm32l496_af.csv b/ports/stm32/boards/stm32l496_af.csv new file mode 100644 index 0000000000..311770a055 --- /dev/null +++ b/ports/stm32/boards/stm32l496_af.csv @@ -0,0 +1,142 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,,, +,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP,DAC +PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5,, +PortA,PA1,,TIM2_CH2,TIM5_CH2,,I2C1_SMBA,SPI1_SCK,,USART2_RTS/USART2_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6,, +PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7,, +PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG2,,SAI1_MCLK_A,TIM15_CH2,EVENTOUT,ADC12_IN8,, +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,DCMI_HSYNC,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9,,DAC1_OUT1 +PortA,PA5,,TIM2_CH1,TIM2_ETR,TIM8_CH1N,,SPI1_SCK,,,,,,,,,LPTIM2_ETR,EVENTOUT,ADC12_IN10,,DAC1_OUT2 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,DCMI_PIXCLK,SPI1_MISO,,USART3_CTS,LPUART1_CTS,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN_COMP2,TIM8_BKIN_COMP2,TIM16_CH1,EVENTOUT,ADC12_IN11,, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,I2C3_SCL,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,,,TIM17_CH1,EVENTOUT,ADC12_IN12,, +PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,SWPMI1_IO,SAI1_SCK_A,LPTIM2_OUT,EVENTOUT,,, +PortA,PA9,,TIM1_CH2,,SPI2_SCK,I2C1_SCL,DCMI_D0,,USART1_TX,,,,LCD_COM1,,SAI1_FS_A,TIM15_BKIN,EVENTOUT,,, +PortA,PA10,,TIM1_CH3,,,I2C1_SDA,DCMI_D1,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,SAI1_SD_A,TIM17_BKIN,EVENTOUT,,, +PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,SPI1_MISO,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,,, +PortA,PA12,,TIM1_ETR,,,,SPI1_MOSI,,USART1_RTS/USART1_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,,, +PortA,PA13,JTMS/SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,SWPMI1_TX,SAI1_SD_B,,EVENTOUT,,, +PortA,PA14,JTCK/SWCLK,LPTIM1_OUT,,,I2C1_SMBA,I2C4_SMBA,,,,,OTG_FS_SOF,,SWPMI1_RX,SAI1_FS_B,,EVENTOUT,,, +PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,USART2_RX,,SPI1_NSS,SPI3_NSS,USART3_RTS/USART3_DE,UART4_RTS/UART4_DE,TSC_G3_IO1,,LCD_SEG17,SWPMI1_SUSPEND,SAI2_FS_B,,EVENTOUT,,, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,SPI1_NSS,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,SAI1_EXTCLK,,EVENTOUT,ADC12_IN15,, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATIN0,USART3_RTS/USART3_DE,LPUART1_RTS/LPUART1_DE,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INM, +PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM1_CKIN0,,,,,LCD_VLCD,,,,EVENTOUT,,COMP1_INP, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS/USART1_DE,,,OTG_FS_CRS_SYNC,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM, +PortB,PB4,NJTRST,,TIM3_CH1,,I2C3_SDA,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS/UART5_DE,TSC_G2_IO1,DCMI_D12,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP, +PortB,PB5,,LPTIM1_IN1,TIM3_CH2,CAN2_RX,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,DCMI_D10,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,,, +PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,I2C4_SCL,DFSDM1_DATIN5,USART1_TX,CAN2_TX,TSC_G2_IO3,DCMI_D5,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP, +PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,I2C4_SDA,DFSDM1_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,DCMI_VSYNC,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM, +PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM1_DATIN6,,,CAN1_RX,DCMI_D6,LCD_SEG16,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT,,, +PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM1_CKIN6,,,CAN1_TX,DCMI_D7,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,,, +PortB,PB10,,TIM2_CH3,,I2C4_SCL,I2C2_SCL,SPI2_SCK,DFSDM1_DATIN7,USART3_TX,LPUART1_RX,TSC_SYNC,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,,, +PortB,PB11,,TIM2_CH4,,I2C4_SDA,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_BK1_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,,, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM1_DATIN1,USART3_CK,LPUART1_RTS/LPUART1_DE,TSC_G1_IO1,CAN2_RX,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,,, +PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM1_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,CAN2_TX,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM1_DATIN2,USART3_RTS/USART3_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,,, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM1_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,,, +PortC,PC0,,LPTIM1_IN1,I2C4_SCL,,I2C3_SCL,,DFSDM1_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1,, +PortC,PC1,TRACED0,LPTIM1_OUT,I2C4_SDA,SPI2_MOSI,I2C3_SDA,,DFSDM1_CKIN4,,LPUART1_TX,,QUADSPI_BK2_IO0,LCD_SEG19,,SAI1_SD_A,,EVENTOUT,ADC123_IN2,, +PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM1_CKOUT,,,,QUADSPI_BK2_IO1,LCD_SEG20,,,,EVENTOUT,ADC123_IN3,, +PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,QUADSPI_BK2_IO2,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN4,, +PortC,PC4,,,,,,,,USART3_TX,,,QUADSPI_BK2_IO3,LCD_SEG22,,,,EVENTOUT,ADC12_IN13,COMP1_INM, +PortC,PC5,,,,,,,,USART3_RX,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN14,COMP1_INP, +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,,DFSDM1_CKIN3,,,TSC_G4_IO1,DCMI_D0,LCD_SEG24,SDMMC1_D6,SAI2_MCLK_A,,EVENTOUT,,, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,DFSDM1_DATIN3,,,TSC_G4_IO2,DCMI_D1,LCD_SEG25,SDMMC1_D7,SAI2_MCLK_B,,EVENTOUT,,, +PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,,TSC_G4_IO3,DCMI_D2,LCD_SEG26,SDMMC1_D0,,,EVENTOUT,,, +PortC,PC9,,TIM8_BKIN2,TIM3_CH4,TIM8_CH4,DCMI_D3,,I2C3_SDA,,,TSC_G4_IO4,OTG_FS_NOE,LCD_SEG27,SDMMC1_D1,SAI2_EXTCLK,TIM8_BKIN2_COMP1,EVENTOUT,,, +PortC,PC10,TRACED1,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,DCMI_D8,LCD_COM4/LCD_SEG28/LCD_SEG40,SDMMC1_D2,SAI2_SCK_B,,EVENTOUT,,, +PortC,PC11,,,,,,QUADSPI_BK2_NCS,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,DCMI_D4,LCD_COM5/LCD_SEG29/LCD_SEG41,SDMMC1_D3,SAI2_MCLK_B,,EVENTOUT,,, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI,USART3_CK,UART5_TX,TSC_G3_IO4,DCMI_D9,LCD_COM6/LCD_SEG30/LCD_SEG42,SDMMC1_CK,SAI2_SD_B,,EVENTOUT,,, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,,, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,,, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,,, +PortD,PD0,,,,,,SPI2_NSS,DFSDM1_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,,, +PortD,PD1,,,,,,SPI2_SCK,DFSDM1_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,,, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,USART3_RTS/USART3_DE,UART5_RX,TSC_SYNC,DCMI_D11,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,,, +PortD,PD3,,,,SPI2_SCK,DCMI_D5,SPI2_MISO,DFSDM1_DATIN0,USART2_CTS,,,QUADSPI_BK2_NCS,,FMC_CLK,,,EVENTOUT,,, +PortD,PD4,,,,,,SPI2_MOSI,DFSDM1_CKIN0,USART2_RTS/USART2_DE,,,QUADSPI_BK2_IO0,,FMC_NOE,,,EVENTOUT,,, +PortD,PD5,,,,,,,,USART2_TX,,,QUADSPI_BK2_IO1,,FMC_NWE,,,EVENTOUT,,, +PortD,PD6,,,,,DCMI_D10,QUADSPI_BK2_IO1,DFSDM1_DATIN1,USART2_RX,,,QUADSPI_BK2_IO2,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,,, +PortD,PD7,,,,,,,DFSDM1_CKIN1,USART2_CK,,,QUADSPI_BK2_IO3,,FMC_NE1,,,EVENTOUT,,, +PortD,PD8,,,,,,,,USART3_TX,,,DCMI_HSYNC,LCD_SEG28,FMC_D13,,,EVENTOUT,,, +PortD,PD9,,,,,,,,USART3_RX,,,DCMI_PIXCLK,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,,, +PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,,, +PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,,, +PortD,PD12,,,TIM4_CH1,,I2C4_SCL,,,USART3_RTS/USART3_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,,, +PortD,PD13,,,TIM4_CH2,,I2C4_SDA,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,,, +PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,,, +PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,,, +PortE,PE0,,,TIM4_ETR,,,,,,,,DCMI_D2,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,,, +PortE,PE1,,,,,,,,,,,DCMI_D3,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,,, +PortE,PE2,TRACECLK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,,, +PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,,, +PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM1_DATIN3,,,TSC_G7_IO3,DCMI_D4,,FMC_A20,SAI1_FS_A,,EVENTOUT,,, +PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM1_CKIN3,,,TSC_G7_IO4,DCMI_D6,,FMC_A21,SAI1_SCK_A,,EVENTOUT,,, +PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,DCMI_D7,,FMC_A22,SAI1_SD_A,,EVENTOUT,,, +PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATIN2,,,,,,FMC_D4,SAI1_SD_B,,EVENTOUT,,, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,,,,,FMC_D5,SAI1_SCK_B,,EVENTOUT,,, +PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,,,,,FMC_D6,SAI1_FS_B,,EVENTOUT,,, +PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATIN4,,,TSC_G5_IO1,QUADSPI_CLK,,FMC_D7,SAI1_MCLK_B,,EVENTOUT,,, +PortE,PE11,,TIM1_CH2,,,,,DFSDM1_CKIN4,,,TSC_G5_IO2,QUADSPI_BK1_NCS,,FMC_D8,,,EVENTOUT,,, +PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,DFSDM1_DATIN5,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,FMC_D9,,,EVENTOUT,,, +PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,DFSDM1_CKIN5,,,TSC_G5_IO4,QUADSPI_BK1_IO1,,FMC_D10,,,EVENTOUT,,, +PortE,PE14,,TIM1_CH4,TIM1_BKIN2,TIM1_BKIN2_COMP2,,SPI1_MISO,,,,,QUADSPI_BK1_IO2,,FMC_D11,,,EVENTOUT,,, +PortE,PE15,,TIM1_BKIN,,TIM1_BKIN_COMP1,,SPI1_MOSI,,,,,QUADSPI_BK1_IO3,,FMC_D12,,,EVENTOUT,,, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,,, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,,, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,,, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN6,, +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN7,, +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN8,, +PortF,PF6,,TIM5_ETR,TIM5_CH1,,,,,,,,QUADSPI_BK1_IO3,,,SAI1_SD_B,,EVENTOUT,ADC3_IN9,, +PortF,PF7,,,TIM5_CH2,,,,,,,,QUADSPI_BK1_IO2,,,SAI1_MCLK_B,,EVENTOUT,ADC3_IN10,, +PortF,PF8,,,TIM5_CH3,,,,,,,,QUADSPI_BK1_IO0,,,SAI1_SCK_B,,EVENTOUT,ADC3_IN11,, +PortF,PF9,,,TIM5_CH4,,,,,,,,QUADSPI_BK1_IO1,,,SAI1_FS_B,TIM15_CH1,EVENTOUT,ADC3_IN12,, +PortF,PF10,,,,QUADSPI_CLK,,,,,,,DCMI_D11,,,,TIM15_CH2,EVENTOUT,ADC3_IN13,, +PortF,PF11,,,,,,,,,,,DCMI_D12,,,,,EVENTOUT,,, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,,, +PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATIN6,,,,,,FMC_A7,,,EVENTOUT,,, +PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,TSC_G8_IO1,,,FMC_A8,,,EVENTOUT,,, +PortF,PF15,,,,,I2C4_SDA,,,,,TSC_G8_IO2,,,FMC_A9,,,EVENTOUT,,, +PortG,PG0,,,,,,,,,,TSC_G8_IO3,,,FMC_A10,,,EVENTOUT,,, +PortG,PG1,,,,,,,,,,TSC_G8_IO4,,,FMC_A11,,,EVENTOUT,,, +PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,,, +PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,,, +PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,,, +PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,,, +PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS/LPUART1_DE,,,,,,,EVENTOUT,,, +PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT,SAI1_MCLK_A,,EVENTOUT,,, +PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,,, +PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,,, +PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,,, +PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,,, +PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS/USART1_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,,, +PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,,, +PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,,, +PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,DCMI_D13,,,,,EVENTOUT,,, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH2,,,,QUADSPI_BK2_IO0,,,,,,,,,,,,EVENTOUT,,, +PortH,PH3,,,,,,,,,,,,,,,,EVENTOUT,,, +PortH,PH4,,,,,I2C2_SCL,,,,,,,,,,,EVENTOUT,,, +PortH,PH5,,,,,I2C2_SDA,,,,,,DCMI_PIXCLK,,,,,EVENTOUT,,, +PortH,PH6,,,,,I2C2_SMBA,,,,,,DCMI_D8,,,,,EVENTOUT,,, +PortH,PH7,,,,,I2C3_SCL,,,,,,DCMI_D9,,,,,EVENTOUT,,, +PortH,PH8,,,,,I2C3_SDA,,,,,,DCMI_HSYNC,,,,,EVENTOUT,,, +PortH,PH9,,,,,I2C3_SMBA,,,,,,DCMI_D0,,,,,EVENTOUT,,, +PortH,PH10,,,TIM5_CH1,,,,,,,,DCMI_D1,,,,,EVENTOUT,,, +PortH,PH11,,,TIM5_CH2,,,,,,,,DCMI_D2,,,,,EVENTOUT,,, +PortH,PH12,,,TIM5_CH3,,,,,,,,DCMI_D3,,,,,EVENTOUT,,, +PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,,,,EVENTOUT,,, +PortH,PH14,,,,TIM8_CH2N,,,,,,,DCMI_D4,,,,,EVENTOUT,,, +PortH,PH15,,,,TIM8_CH3N,,,,,,,DCMI_D11,,,,,EVENTOUT,,, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS,,,,,DCMI_D13,,,,,EVENTOUT,,, +PortI,PI1,,,,,,SPI2_SCK,,,,,DCMI_D8,,,,,EVENTOUT,,, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,DCMI_D9,,,,,EVENTOUT,,, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI,,,,,DCMI_D10,,,,,EVENTOUT,,, +PortI,PI4,,,,TIM8_BKIN,,,,,,,DCMI_D5,,,,,EVENTOUT,,, +PortI,PI5,,,,TIM8_CH1,,,,,,,DCMI_VSYNC,,,,,EVENTOUT,,, +PortI,PI6,,,,TIM8_CH2,,,,,,,DCMI_D6,,,,,EVENTOUT,,, +PortI,PI7,,,,TIM8_CH3,,,,,,,DCMI_D7,,,,,EVENTOUT,,, +PortI,PI8,,,,,,,,,,,DCMI_D12,,,,,EVENTOUT,,, +PortI,PI9,,,,,,,,,,CAN1_RX,,,,,,EVENTOUT,,, +PortI,PI10,,,,,,,,,,,,,,,,EVENTOUT,,, +PortI,PI11,,,,,,,,,,,,,,,,EVENTOUT,,, diff --git a/ports/stm32/boards/stm32l496xg.ld b/ports/stm32/boards/stm32l496xg.ld new file mode 100644 index 0000000000..88221170b4 --- /dev/null +++ b/ports/stm32/boards/stm32l496xg.ld @@ -0,0 +1,35 @@ +/* + GNU linker script for STM32L496XG +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sectors 0-7 */ + FLASH_TEXT (rx) : ORIGIN = 0x08004000, LENGTH = 596K /* sectors 8-305 */ + FLASH_FS (r) : ORIGIN = 0x08099000, LENGTH = 412K /* sectors 306-511 412 KiB */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K + SRAM2 (xrw) : ORIGIN = 0x20040000, LENGTH = 62K /* leave 2K for flash fs cache */ + FS_CACHE(xrw) : ORIGIN = 0x2004f800, LENGTH = 2K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define the top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2); + +/* RAM extents for the garbage collector */ +_ram_fs_cache_start = ORIGIN(FS_CACHE); +_ram_fs_cache_block_size = LENGTH(FS_CACHE); +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = 0x2001C000; /* tunable */ + +_flash_fs_start = ORIGIN(FLASH_FS); +_flash_fs_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/bufhelper.h b/ports/stm32/bufhelper.h index c1967bf430..12c79c2fda 100644 --- a/ports/stm32/bufhelper.h +++ b/ports/stm32/bufhelper.h @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_BUFHELPER_H -#define MICROPY_INCLUDED_STMHAL_BUFHELPER_H +#ifndef MICROPY_INCLUDED_STM32_BUFHELPER_H +#define MICROPY_INCLUDED_STM32_BUFHELPER_H void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data); mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, vstr_t *vstr); -#endif // MICROPY_INCLUDED_STMHAL_BUFHELPER_H +#endif // MICROPY_INCLUDED_STM32_BUFHELPER_H diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 25a608ce9b..7680b0de42 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014 Damien P. George + * Copyright (c) 2014-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,8 +29,10 @@ #include #include "py/objtuple.h" +#include "py/objarray.h" #include "py/runtime.h" #include "py/gc.h" +#include "py/binary.h" #include "py/stream.h" #include "py/mperrno.h" #include "py/mphal.h" @@ -45,6 +47,14 @@ #define MASK32 (2) #define LIST32 (3) +enum { + CAN_STATE_STOPPED, + CAN_STATE_ERROR_ACTIVE, + CAN_STATE_ERROR_WARNING, + CAN_STATE_ERROR_PASSIVE, + CAN_STATE_BUS_OFF, +}; + /// \moduleref pyb /// \class CAN - controller area network communication bus /// @@ -81,6 +91,9 @@ typedef struct _pyb_can_obj_t { bool extframe : 1; byte rx_state0; byte rx_state1; + uint16_t num_error_warning; + uint16_t num_error_passive; + uint16_t num_bus_off; CAN_HandleTypeDef can; } pyb_can_obj_t; @@ -91,49 +104,57 @@ STATIC uint8_t can2_start_bank = 14; // assumes Init parameters have been set up correctly STATIC bool can_init(pyb_can_obj_t *can_obj) { CAN_TypeDef *CANx = NULL; - - uint32_t GPIO_Pin = 0; - uint8_t GPIO_AF_CANx = 0; - GPIO_TypeDef* GPIO_Port = NULL; + uint32_t sce_irq = 0; + const pin_obj_t *pins[2]; switch (can_obj->can_id) { - // CAN1 is on RX,TX = Y3,Y4 = PB9,PB9 + #if defined(MICROPY_HW_CAN1_TX) case PYB_CAN_1: CANx = CAN1; - GPIO_AF_CANx = GPIO_AF9_CAN1; - GPIO_Port = GPIOB; - GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9; + sce_irq = CAN1_SCE_IRQn; + pins[0] = MICROPY_HW_CAN1_TX; + pins[1] = MICROPY_HW_CAN1_RX; __CAN1_CLK_ENABLE(); break; + #endif - // CAN2 is on RX,TX = Y5,Y6 = PB12,PB13 + #if defined(MICROPY_HW_CAN2_TX) case PYB_CAN_2: CANx = CAN2; - GPIO_AF_CANx = GPIO_AF9_CAN2; - GPIO_Port = GPIOB; - GPIO_Pin = GPIO_PIN_12 | GPIO_PIN_13; + sce_irq = CAN2_SCE_IRQn; + pins[0] = MICROPY_HW_CAN2_TX; + pins[1] = MICROPY_HW_CAN2_RX; __CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well __CAN2_CLK_ENABLE(); break; + #endif default: return false; } // init GPIO - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Pin = GPIO_Pin; - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_PULLUP; - GPIO_InitStructure.Alternate = GPIO_AF_CANx; - HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure); + uint32_t mode = MP_HAL_PIN_MODE_ALT; + uint32_t pull = MP_HAL_PIN_PULL_UP; + for (int i = 0; i < 2; i++) { + if (!mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_CAN, can_obj->can_id)) { + return false; + } + } // init CANx can_obj->can.Instance = CANx; HAL_CAN_Init(&can_obj->can); can_obj->is_enabled = true; + can_obj->num_error_warning = 0; + can_obj->num_error_passive = 0; + can_obj->num_bus_off = 0; + + __HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG); + + NVIC_SetPriority(sce_irq, IRQ_PRI_CAN); + HAL_NVIC_EnableIRQ(sce_irq); return true; } @@ -170,6 +191,51 @@ STATIC void can_clearfilter(uint32_t f) { HAL_CAN_ConfigFilter(NULL, &filter); } +STATIC int can_receive(CAN_TypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint32_t timeout_ms) { + volatile uint32_t *rfr; + if (fifo == CAN_FIFO0) { + rfr = &can->RF0R; + } else { + rfr = &can->RF1R; + } + + // Wait for a message to become available, with timeout + uint32_t start = HAL_GetTick(); + while ((*rfr & 3) == 0) { + MICROPY_EVENT_POLL_HOOK + if (HAL_GetTick() - start >= timeout_ms) { + return -MP_ETIMEDOUT; + } + } + + // Read message data + CAN_FIFOMailBox_TypeDef *box = &can->sFIFOMailBox[fifo]; + msg->IDE = box->RIR & 4; + if (msg->IDE == CAN_ID_STD) { + msg->StdId = box->RIR >> 21; + } else { + msg->ExtId = box->RIR >> 3; + } + msg->RTR = box->RIR & 2; + msg->DLC = box->RDTR & 0xf; + msg->FMI = box->RDTR >> 8 & 0xff; + uint32_t rdlr = box->RDLR; + msg->Data[0] = rdlr; + msg->Data[1] = rdlr >> 8; + msg->Data[2] = rdlr >> 16; + msg->Data[3] = rdlr >> 24; + uint32_t rdhr = box->RDHR; + msg->Data[4] = rdhr; + msg->Data[5] = rdhr >> 8; + msg->Data[6] = rdhr >> 16; + msg->Data[7] = rdhr >> 24; + + // Release (free) message from FIFO + *rfr |= CAN_RF0R_RFOM0; + + return 0; // success +} + // We have our own version of CAN transmit so we can handle Timeout=0 correctly. STATIC HAL_StatusTypeDef CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout) { uint32_t transmitmailbox; @@ -268,7 +334,6 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki if (!self->is_enabled) { mp_printf(print, "CAN(%u)", self->can_id); } else { - mp_printf(print, "CAN(%u, CAN.", self->can_id); qstr mode; switch (self->can.Init.Mode) { case CAN_MODE_NORMAL: mode = MP_QSTR_NORMAL; break; @@ -276,18 +341,17 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki case CAN_MODE_SILENT: mode = MP_QSTR_SILENT; break; case CAN_MODE_SILENT_LOOPBACK: default: mode = MP_QSTR_SILENT_LOOPBACK; break; } - mp_printf(print, "%q, extframe=", mode); - if (self->extframe) { - mode = MP_QSTR_True; - } else { - mode = MP_QSTR_False; - } - mp_printf(print, "%q)", mode); + mp_printf(print, "CAN(%u, CAN.%q, extframe=%q, auto_restart=%q)", + self->can_id, + mode, + self->extframe ? MP_QSTR_True : MP_QSTR_False, + (self->can.Instance->MCR & CAN_MCR_ABOM) ? MP_QSTR_True : MP_QSTR_False); } } // init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8) STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_extframe, ARG_prescaler, ARG_sjw, ARG_bs1, ARG_bs2, ARG_auto_restart }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_MODE_NORMAL} }, { MP_QSTR_extframe, MP_ARG_BOOL, {.u_bool = false} }, @@ -295,24 +359,25 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp { MP_QSTR_sjw, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_bs1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 6} }, { MP_QSTR_bs2, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_auto_restart, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; // parse args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - self->extframe = args[1].u_bool; + self->extframe = args[ARG_extframe].u_bool; // set the CAN configuration values memset(&self->can, 0, sizeof(self->can)); CAN_InitTypeDef *init = &self->can.Init; - init->Mode = args[0].u_int << 4; // shift-left so modes fit in a small-int - init->Prescaler = args[2].u_int; - init->SJW = ((args[3].u_int - 1) & 3) << 24; - init->BS1 = ((args[4].u_int - 1) & 0xf) << 16; - init->BS2 = ((args[5].u_int - 1) & 7) << 20; + init->Mode = args[ARG_mode].u_int << 4; // shift-left so modes fit in a small-int + init->Prescaler = args[ARG_prescaler].u_int; + init->SJW = ((args[ARG_sjw].u_int - 1) & 3) << 24; + init->BS1 = ((args[ARG_bs1].u_int - 1) & 0xf) << 16; + init->BS2 = ((args[ARG_bs2].u_int - 1) & 7) << 20; init->TTCM = DISABLE; - init->ABOM = DISABLE; + init->ABOM = args[ARG_auto_restart].u_bool ? ENABLE : DISABLE; init->AWUM = DISABLE; init->NART = DISABLE; init->RFLM = DISABLE; @@ -413,20 +478,91 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { if (self->can.Instance == CAN1) { HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN1_SCE_IRQn); __CAN1_FORCE_RESET(); __CAN1_RELEASE_RESET(); __CAN1_CLK_DISABLE(); + #if defined(CAN2) } else if (self->can.Instance == CAN2) { HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN2_SCE_IRQn); __CAN2_FORCE_RESET(); __CAN2_RELEASE_RESET(); __CAN2_CLK_DISABLE(); + #endif } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_deinit_obj, pyb_can_deinit); +// Force a software restart of the controller, to allow transmission after a bus error +STATIC mp_obj_t pyb_can_restart(mp_obj_t self_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!self->is_enabled) { + mp_raise_ValueError(NULL); + } + CAN_TypeDef *can = self->can.Instance; + can->MCR |= CAN_MCR_INRQ; + while ((can->MSR & CAN_MSR_INAK) == 0) { + } + can->MCR &= ~CAN_MCR_INRQ; + while ((can->MSR & CAN_MSR_INAK)) { + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_restart_obj, pyb_can_restart); + +// Get the state of the controller +STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t state = CAN_STATE_STOPPED; + if (self->is_enabled) { + CAN_TypeDef *can = self->can.Instance; + if (can->ESR & CAN_ESR_BOFF) { + state = CAN_STATE_BUS_OFF; + } else if (can->ESR & CAN_ESR_EPVF) { + state = CAN_STATE_ERROR_PASSIVE; + } else if (can->ESR & CAN_ESR_EWGF) { + state = CAN_STATE_ERROR_WARNING; + } else { + state = CAN_STATE_ERROR_ACTIVE; + } + } + return MP_OBJ_NEW_SMALL_INT(state); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state); + +// Get info about error states and TX/RX buffers +STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_obj_list_t *list; + if (n_args == 1) { + list = MP_OBJ_TO_PTR(mp_obj_new_list(8, NULL)); + } else { + if (!MP_OBJ_IS_TYPE(args[1], &mp_type_list)) { + mp_raise_TypeError(NULL); + } + list = MP_OBJ_TO_PTR(args[1]); + if (list->len < 8) { + mp_raise_ValueError(NULL); + } + } + CAN_TypeDef *can = self->can.Instance; + uint32_t esr = can->ESR; + list->items[0] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_TEC_Pos & 0xff); + list->items[1] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_REC_Pos & 0xff); + list->items[2] = MP_OBJ_NEW_SMALL_INT(self->num_error_warning); + list->items[3] = MP_OBJ_NEW_SMALL_INT(self->num_error_passive); + list->items[4] = MP_OBJ_NEW_SMALL_INT(self->num_bus_off); + int n_tx_pending = 0x01121223 >> ((can->TSR >> CAN_TSR_TME_Pos & 7) << 2) & 0xf; + list->items[5] = MP_OBJ_NEW_SMALL_INT(n_tx_pending); + list->items[6] = MP_OBJ_NEW_SMALL_INT(can->RF0R >> CAN_RF0R_FMP0_Pos & 3); + list->items[7] = MP_OBJ_NEW_SMALL_INT(can->RF1R >> CAN_RF1R_FMP1_Pos & 3); + return MP_OBJ_FROM_PTR(list); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_can_info_obj, 1, 2, pyb_can_info); + /// \method any(fifo) /// Return `True` if any message waiting on the FIFO, else `False`. STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) { @@ -454,6 +590,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any); /// /// Return value: `None`. STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_data, ARG_id, ARG_timeout, ARG_rtr }; static const mp_arg_t allowed_args[] = { { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, @@ -469,7 +606,7 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // get the buffer to send from mp_buffer_info_t bufinfo; uint8_t data[1]; - pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); + pyb_buf_get_for_send(args[ARG_data].u_obj, &bufinfo, data); if (bufinfo.len > 8) { mp_raise_ValueError("CAN data field too long"); @@ -478,13 +615,13 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // send the data CanTxMsgTypeDef tx_msg; if (self->extframe) { - tx_msg.ExtId = args[1].u_int & 0x1FFFFFFF; + tx_msg.ExtId = args[ARG_id].u_int & 0x1FFFFFFF; tx_msg.IDE = CAN_ID_EXT; } else { - tx_msg.StdId = args[1].u_int & 0x7FF; + tx_msg.StdId = args[ARG_id].u_int & 0x7FF; tx_msg.IDE = CAN_ID_STD; } - if (args[3].u_bool == false) { + if (args[ARG_rtr].u_bool == false) { tx_msg.RTR = CAN_RTR_DATA; } else { tx_msg.RTR = CAN_RTR_REMOTE; @@ -495,7 +632,7 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } self->can.pTxMsg = &tx_msg; - HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[2].u_int); + HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[ARG_timeout].u_int); if (status != HAL_OK) { mp_hal_raise(status); @@ -505,17 +642,20 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send); -/// \method recv(fifo, *, timeout=5000) +/// \method recv(fifo, list=None, *, timeout=5000) /// /// Receive data on the bus: /// /// - `fifo` is an integer, which is the FIFO to receive on +/// - `list` if not None is a list with at least 4 elements /// - `timeout` is the timeout in milliseconds to wait for the receive. /// /// Return value: buffer of data bytes. STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_fifo, ARG_list, ARG_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_list, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; @@ -526,57 +666,82 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // receive the data CanRxMsgTypeDef rx_msg; - self->can.pRxMsg = self->can.pRx1Msg = &rx_msg; - HAL_StatusTypeDef status = HAL_CAN_Receive(&self->can, args[0].u_int, args[1].u_int); - - if (status != HAL_OK) { - mp_hal_raise(status); + int ret = can_receive(self->can.Instance, args[ARG_fifo].u_int, &rx_msg, args[ARG_timeout].u_int); + if (ret < 0) { + mp_raise_OSError(-ret); } // Manage the rx state machine - if ((args[0].u_int == CAN_FIFO0 && self->rxcallback0 != mp_const_none) || - (args[0].u_int == CAN_FIFO1 && self->rxcallback1 != mp_const_none)) { - byte *state = (args[0].u_int == CAN_FIFO0) ? &self->rx_state0 : &self->rx_state1; + mp_int_t fifo = args[ARG_fifo].u_int; + if ((fifo == CAN_FIFO0 && self->rxcallback0 != mp_const_none) || + (fifo == CAN_FIFO1 && self->rxcallback1 != mp_const_none)) { + byte *state = (fifo == CAN_FIFO0) ? &self->rx_state0 : &self->rx_state1; switch (*state) { case RX_STATE_FIFO_EMPTY: break; case RX_STATE_MESSAGE_PENDING: - if (__HAL_CAN_MSG_PENDING(&self->can, args[0].u_int) == 0) { + if (__HAL_CAN_MSG_PENDING(&self->can, fifo) == 0) { // Fifo is empty - __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1); *state = RX_STATE_FIFO_EMPTY; } break; case RX_STATE_FIFO_FULL: - __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); *state = RX_STATE_MESSAGE_PENDING; break; case RX_STATE_FIFO_OVERFLOW: - __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1); - __HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); *state = RX_STATE_MESSAGE_PENDING; break; } } - // return the received data - // TODO use a namedtuple (when namedtuple types can be stored in ROM) - mp_obj_tuple_t *tuple = mp_obj_new_tuple(4, NULL); - if (rx_msg.IDE == CAN_ID_STD) { - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); + // Create the tuple, or get the list, that will hold the return values + // Also populate the fourth element, either a new bytes or reuse existing memoryview + mp_obj_t ret_obj = args[ARG_list].u_obj; + mp_obj_t *items; + if (ret_obj == mp_const_none) { + ret_obj = mp_obj_new_tuple(4, NULL); + items = ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(ret_obj))->items; + items[3] = mp_obj_new_bytes(&rx_msg.Data[0], rx_msg.DLC); } else { - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); + // User should provide a list of length at least 4 to hold the values + if (!MP_OBJ_IS_TYPE(ret_obj, &mp_type_list)) { + mp_raise_TypeError(NULL); + } + mp_obj_list_t *list = MP_OBJ_TO_PTR(ret_obj); + if (list->len < 4) { + mp_raise_ValueError(NULL); + } + items = list->items; + // Fourth element must be a memoryview which we assume points to a + // byte-like array which is large enough, and then we resize it inplace + if (!MP_OBJ_IS_TYPE(items[3], &mp_type_memoryview)) { + mp_raise_TypeError(NULL); + } + mp_obj_array_t *mv = MP_OBJ_TO_PTR(items[3]); + if (!(mv->typecode == (MP_OBJ_ARRAY_TYPECODE_FLAG_RW | BYTEARRAY_TYPECODE) + || (mv->typecode | 0x20) == (MP_OBJ_ARRAY_TYPECODE_FLAG_RW | 'b'))) { + mp_raise_ValueError(NULL); + } + mv->len = rx_msg.DLC; + memcpy(mv->items, &rx_msg.Data[0], rx_msg.DLC); } - tuple->items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; - tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); - vstr_t vstr; - vstr_init_len(&vstr, rx_msg.DLC); - for (mp_uint_t i = 0; i < rx_msg.DLC; i++) { - vstr.buf[i] = rx_msg.Data[i]; // Data is uint32_t but holds only 1 byte + + // Populate the first 3 values of the tuple/list + if (rx_msg.IDE == CAN_ID_STD) { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); + } else { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); } - tuple->items[3] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); - return tuple; + items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; + items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); + + // Return the result + return ret_obj; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv); @@ -617,6 +782,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_clearfilter_obj, pyb_can_clearfilter); /// Return value: `None`. #define EXTENDED_ID_TO_16BIT_FILTER(id) (((id & 0xC00000) >> 13) | ((id & 0x38000) >> 15)) | 8 STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_bank, ARG_mode, ARG_fifo, ARG_params, ARG_rtr }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bank, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, @@ -635,20 +801,20 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma mp_uint_t rtr_masks[4] = {0, 0, 0, 0}; mp_obj_t *rtr_flags; mp_obj_t *params; - mp_obj_get_array(args[3].u_obj, &len, ¶ms); - if (args[4].u_obj != MP_OBJ_NULL){ - mp_obj_get_array(args[4].u_obj, &rtr_len, &rtr_flags); + mp_obj_get_array(args[ARG_params].u_obj, &len, ¶ms); + if (args[ARG_rtr].u_obj != MP_OBJ_NULL){ + mp_obj_get_array(args[ARG_rtr].u_obj, &rtr_len, &rtr_flags); } CAN_FilterConfTypeDef filter; - if (args[1].u_int == MASK16 || args[1].u_int == LIST16) { + if (args[ARG_mode].u_int == MASK16 || args[ARG_mode].u_int == LIST16) { if (len != 4) { goto error; } filter.FilterScale = CAN_FILTERSCALE_16BIT; if (self->extframe) { - if (args[4].u_obj != MP_OBJ_NULL) { - if (args[1].u_int == MASK16) { + if (args[ARG_rtr].u_obj != MP_OBJ_NULL) { + if (args[ARG_mode].u_int == MASK16) { rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; rtr_masks[1] = 0x02; rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0; @@ -665,8 +831,8 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma filter.FilterIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])) | rtr_masks[2]; // id2 filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])) | rtr_masks[3]; // mask2 } else { // Basic frames - if (args[4].u_obj != MP_OBJ_NULL) { - if (args[1].u_int == MASK16) { + if (args[ARG_rtr].u_obj != MP_OBJ_NULL) { + if (args[ARG_mode].u_int == MASK16) { rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0; rtr_masks[1] = 0x10; rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0; @@ -683,20 +849,20 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma filter.FilterIdHigh = (mp_obj_get_int(params[2]) << 5) | rtr_masks[2]; // id2 filter.FilterMaskIdHigh = (mp_obj_get_int(params[3]) << 5) | rtr_masks[3]; // mask2 } - if (args[1].u_int == MASK16) { + if (args[ARG_mode].u_int == MASK16) { filter.FilterMode = CAN_FILTERMODE_IDMASK; } - if (args[1].u_int == LIST16) { + if (args[ARG_mode].u_int == LIST16) { filter.FilterMode = CAN_FILTERMODE_IDLIST; } } - else if (args[1].u_int == MASK32 || args[1].u_int == LIST32) { + else if (args[ARG_mode].u_int == MASK32 || args[ARG_mode].u_int == LIST32) { if (len != 2) { goto error; } filter.FilterScale = CAN_FILTERSCALE_32BIT; - if (args[4].u_obj != MP_OBJ_NULL) { - if (args[1].u_int == MASK32) { + if (args[ARG_rtr].u_obj != MP_OBJ_NULL) { + if (args[ARG_mode].u_int == MASK32) { rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; rtr_masks[1] = 0x02; } else { // LIST32 @@ -708,18 +874,18 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma filter.FilterIdLow = (((mp_obj_get_int(params[0]) & 0x00001FFF) << 3) | 4) | rtr_masks[0]; filter.FilterMaskIdHigh = (mp_obj_get_int(params[1]) & 0x1FFFE000 ) >> 13; filter.FilterMaskIdLow = (((mp_obj_get_int(params[1]) & 0x00001FFF) << 3) | 4) | rtr_masks[1]; - if (args[1].u_int == MASK32) { + if (args[ARG_mode].u_int == MASK32) { filter.FilterMode = CAN_FILTERMODE_IDMASK; } - if (args[1].u_int == LIST32) { + if (args[ARG_mode].u_int == LIST32) { filter.FilterMode = CAN_FILTERMODE_IDLIST; } } else { goto error; } - filter.FilterFIFOAssignment = args[2].u_int; // fifo - filter.FilterNumber = args[0].u_int; // bank + filter.FilterFIFOAssignment = args[ARG_fifo].u_int; + filter.FilterNumber = args[ARG_bank].u_int; if (self->can_id == 1) { if (filter.FilterNumber >= can2_start_bank) { goto error; @@ -760,13 +926,15 @@ STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t *callback = callback_in; } else if (mp_obj_is_callable(callback_in)) { *callback = callback_in; - uint32_t irq; + uint32_t irq = 0; if (self->can_id == PYB_CAN_1) { irq = (fifo == 0) ? CAN1_RX0_IRQn : CAN1_RX1_IRQn; + #if defined(CAN2) } else { irq = (fifo == 0) ? CAN2_RX0_IRQn : CAN2_RX1_IRQn; + #endif } - HAL_NVIC_SetPriority(irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN); + NVIC_SetPriority(irq, IRQ_PRI_CAN); HAL_NVIC_EnableIRQ(irq); __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1); __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1); @@ -780,6 +948,9 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { // instance methods { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_can_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&pyb_can_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_can_info_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) }, @@ -799,6 +970,13 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_LIST16), MP_ROM_INT(LIST16) }, { MP_ROM_QSTR(MP_QSTR_MASK32), MP_ROM_INT(MASK32) }, { MP_ROM_QSTR(MP_QSTR_LIST32), MP_ROM_INT(LIST32) }, + + // values for CAN.state() + { MP_ROM_QSTR(MP_QSTR_STOPPED), MP_ROM_INT(CAN_STATE_STOPPED) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_ACTIVE), MP_ROM_INT(CAN_STATE_ERROR_ACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_WARNING), MP_ROM_INT(CAN_STATE_ERROR_WARNING) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_PASSIVE), MP_ROM_INT(CAN_STATE_ERROR_PASSIVE) }, + { MP_ROM_QSTR(MP_QSTR_BUS_OFF), MP_ROM_INT(CAN_STATE_BUS_OFF) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_can_locals_dict, pyb_can_locals_dict_table); @@ -881,6 +1059,21 @@ void can_rx_irq_handler(uint can_id, uint fifo_id) { } } +void can_sce_irq_handler(uint can_id) { + pyb_can_obj_t *self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1]; + if (self) { + self->can.Instance->MSR = CAN_MSR_ERRI; + uint32_t esr = self->can.Instance->ESR; + if (esr & CAN_ESR_BOFF) { + ++self->num_bus_off; + } else if (esr & CAN_ESR_EPVF) { + ++self->num_error_passive; + } else if (esr & CAN_ESR_EWGF) { + ++self->num_error_warning; + } + } +} + STATIC const mp_stream_p_t can_stream_p = { //.read = can_read, // is read sensible for CAN? //.write = can_write, // is write sensible for CAN? diff --git a/ports/stm32/can.h b/ports/stm32/can.h index 8600128139..54e7deaa5e 100644 --- a/ports/stm32/can.h +++ b/ports/stm32/can.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_CAN_H -#define MICROPY_INCLUDED_STMHAL_CAN_H +#ifndef MICROPY_INCLUDED_STM32_CAN_H +#define MICROPY_INCLUDED_STM32_CAN_H #define PYB_CAN_1 (1) #define PYB_CAN_2 (2) @@ -34,5 +34,6 @@ extern const mp_obj_type_t pyb_can_type; void can_init0(void); void can_deinit(void); void can_rx_irq_handler(uint can_id, uint fifo_id); +void can_sce_irq_handler(uint can_id); -#endif // MICROPY_INCLUDED_STMHAL_CAN_H +#endif // MICROPY_INCLUDED_STM32_CAN_H diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 268b1bcfb6..559bb0b0d0 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -29,11 +29,11 @@ #include #include "py/runtime.h" +#include "py/mphal.h" #include "timer.h" #include "dac.h" #include "dma.h" #include "pin.h" -#include "genhdr/pins.h" /// \moduleref pyb /// \class DAC - digital to analog conversion @@ -66,6 +66,10 @@ #if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC +#if defined(STM32H7) +#define DAC DAC1 +#endif + STATIC DAC_HandleTypeDef DAC_Handle; void dac_init(void) { @@ -102,10 +106,14 @@ STATIC uint32_t TIMx_Config(mp_obj_t timer) { // work out the trigger channel (only certain ones are supported) if (tim->Instance == TIM2) { return DAC_TRIGGER_T2_TRGO; + #if defined(TIM4) } else if (tim->Instance == TIM4) { return DAC_TRIGGER_T4_TRGO; + #endif + #if defined(TIM5) } else if (tim->Instance == TIM5) { return DAC_TRIGGER_T5_TRGO; + #endif #if defined(TIM6) } else if (tim->Instance == TIM6) { return DAC_TRIGGER_T6_TRGO; @@ -137,14 +145,24 @@ typedef struct _pyb_dac_obj_t { mp_obj_base_t base; uint32_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2 const dma_descr_t *tx_dma_descr; - uint16_t pin; // GPIO_PIN_4 or GPIO_PIN_5 + mp_hal_pin_obj_t pin; // pin_A4 or pin_A5 uint8_t bits; // 8 or 12 uint8_t state; + uint8_t outbuf_single; + uint8_t outbuf_waveform; } pyb_dac_obj_t; +STATIC void pyb_dac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_dac_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "DAC(%u, bits=%u)", + self->dac_channel == DAC_CHANNEL_1 ? 1 : 2, + self->bits); +} + STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_buffering, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, }; // parse args @@ -152,23 +170,21 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // GPIO configuration - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Pin = self->pin; - GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; - GPIO_InitStructure.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + mp_hal_pin_config(self->pin, MP_HAL_PIN_MODE_ANALOG, MP_HAL_PIN_PULL_NONE, 0); // DAC peripheral clock - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) __DAC_CLK_ENABLE(); - #elif defined(MCU_SERIES_L4) + #elif defined(STM32H7) + __HAL_RCC_DAC12_CLK_ENABLE(); + #elif defined(STM32F0) || defined(STM32L4) __HAL_RCC_DAC1_CLK_ENABLE(); #else #error Unsupported Processor #endif // stop anything already going on - __DMA1_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); DMA_HandleTypeDef DMA_Handle; /* Get currently configured dma */ dma_init_handle(&DMA_Handle, self->tx_dma_descr, (void*)NULL); @@ -189,6 +205,19 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp mp_raise_ValueError("unsupported bits"); } + // set output buffer config + if (args[1].u_obj == mp_const_none) { + // due to legacy, default values differ for single and waveform outputs + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else if (mp_obj_is_true(args[1].u_obj)) { + self->outbuf_single = DAC_OUTPUTBUFFER_ENABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else { + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_DISABLE; + } + // reset state of DAC self->state = DAC_STATE_RESET; @@ -213,9 +242,9 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_ dac_id = mp_obj_get_int(args[0]); } else { const pin_obj_t *pin = pin_find(args[0]); - if (pin == &pin_A4) { + if (pin == pin_A4) { dac_id = 1; - } else if (pin == &pin_A5) { + } else if (pin == pin_A5) { dac_id = 2; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%q) doesn't have DAC capabilities", pin->name)); @@ -226,11 +255,11 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_ dac->base.type = &pyb_dac_type; if (dac_id == 1) { - dac->pin = GPIO_PIN_4; + dac->pin = pin_A4; dac->dac_channel = DAC_CHANNEL_1; dac->tx_dma_descr = &dma_DAC_1_TX; } else if (dac_id == 2) { - dac->pin = GPIO_PIN_5; + dac->pin = pin_A5; dac->dac_channel = DAC_CHANNEL_2; dac->tx_dma_descr = &dma_DAC_2_TX; } else { @@ -257,10 +286,18 @@ STATIC mp_obj_t pyb_dac_deinit(mp_obj_t self_in) { pyb_dac_obj_t *self = self_in; if (self->dac_channel == DAC_CHANNEL_1) { DAC_Handle.Instance->CR &= ~DAC_CR_EN1; + #if defined(STM32H7) || defined(STM32L4) + DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE1_Pos)) | 2 << DAC_MCR_MODE1_Pos; + #else DAC_Handle.Instance->CR |= DAC_CR_BOFF1; + #endif } else { DAC_Handle.Instance->CR &= ~DAC_CR_EN2; + #if defined(STM32H7) || defined(STM32L4) + DAC->MCR = (DAC->MCR & ~(7 << DAC_MCR_MODE2_Pos)) | 2 << DAC_MCR_MODE2_Pos; + #else DAC_Handle.Instance->CR |= DAC_CR_BOFF2; + #endif } return mp_const_none; } @@ -280,7 +317,7 @@ STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) { // configure DAC to trigger via TIM6 DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_BUILTIN_WAVEFORM; } @@ -310,7 +347,7 @@ STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { // configure DAC to trigger via TIM6 DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_BUILTIN_WAVEFORM; } @@ -333,7 +370,7 @@ STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) { if (self->state != DAC_STATE_WRITE_SINGLE) { DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_NONE; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE; + config.DAC_OutputBuffer = self->outbuf_single; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_WRITE_SINGLE; } @@ -395,7 +432,7 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t * dac_trigger = TIMx_Config(args[1].u_obj); } - __DMA1_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); DMA_HandleTypeDef DMA_Handle; /* Get currently configured dma */ @@ -445,7 +482,7 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t * if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) { DAC_ChannelConfTypeDef config; config.DAC_Trigger = dac_trigger; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger; } @@ -499,6 +536,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_dac_locals_dict, pyb_dac_locals_dict_table); const mp_obj_type_t pyb_dac_type = { { &mp_type_type }, .name = MP_QSTR_DAC, + .print = pyb_dac_print, .make_new = pyb_dac_make_new, .locals_dict = (mp_obj_dict_t*)&pyb_dac_locals_dict, }; diff --git a/ports/stm32/dac.h b/ports/stm32/dac.h index f487f52a92..1d8f0ab61e 100644 --- a/ports/stm32/dac.h +++ b/ports/stm32/dac.h @@ -23,11 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_DAC_H -#define MICROPY_INCLUDED_STMHAL_DAC_H +#ifndef MICROPY_INCLUDED_STM32_DAC_H +#define MICROPY_INCLUDED_STM32_DAC_H void dac_init(void); extern const mp_obj_type_t pyb_dac_type; -#endif // MICROPY_INCLUDED_STMHAL_DAC_H +#endif // MICROPY_INCLUDED_STM32_DAC_H diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index df6275d652..dc1ad6c1cd 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -52,10 +52,10 @@ typedef enum { dma_id_15, } dma_id_t; -typedef struct _dma_descr_t { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +struct _dma_descr_t { + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) DMA_Stream_TypeDef *instance; - #elif defined(MCU_SERIES_L4) + #elif defined(STM32F0) || defined(STM32L4) DMA_Channel_TypeDef *instance; #else #error "Unsupported Processor" @@ -64,14 +64,14 @@ typedef struct _dma_descr_t { uint32_t transfer_direction; // periph to memory or vice-versa dma_id_t id; const DMA_InitTypeDef *init; -} dma_descr_t; +}; // Default parameters to dma_init() shared by spi and i2c; Channel and Direction // vary depending on the peripheral instance so they get passed separately static const DMA_InitTypeDef dma_init_struct_spi_i2c = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -81,7 +81,7 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { .MemDataAlignment = DMA_MDATAALIGN_BYTE, .Mode = DMA_NORMAL, .Priority = DMA_PRIORITY_LOW, - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .FIFOMode = DMA_FIFOMODE_DISABLE, .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, .MemBurst = DMA_MBURST_INC4, @@ -89,12 +89,12 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { #endif }; -#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD && !defined(STM32H7) // Parameters to dma_init() for SDIO tx and rx. static const DMA_InitTypeDef dma_init_struct_sdio = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -102,13 +102,13 @@ static const DMA_InitTypeDef dma_init_struct_sdio = { .MemInc = DMA_MINC_ENABLE, .PeriphDataAlignment = DMA_PDATAALIGN_WORD, .MemDataAlignment = DMA_MDATAALIGN_WORD, - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .Mode = DMA_PFCTRL, - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) .Mode = DMA_NORMAL, #endif .Priority = DMA_PRIORITY_VERY_HIGH, - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .FIFOMode = DMA_FIFOMODE_ENABLE, .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, .MemBurst = DMA_MBURST_INC4, @@ -120,9 +120,9 @@ static const DMA_InitTypeDef dma_init_struct_sdio = { #if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC // Default parameters to dma_init() for DAC tx static const DMA_InitTypeDef dma_init_struct_dac = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -132,7 +132,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = { .MemDataAlignment = DMA_MDATAALIGN_BYTE, .Mode = DMA_NORMAL, .Priority = DMA_PRIORITY_HIGH, - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .FIFOMode = DMA_FIFOMODE_DISABLE, .FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL, .MemBurst = DMA_MBURST_SINGLE, @@ -141,7 +141,46 @@ static const DMA_InitTypeDef dma_init_struct_dac = { }; #endif -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F0) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (7) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (dma_channel) + +#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponfing to DMA1 (7 channels) +#define DMA2_ENABLE_MASK (0x0f80) // Bits in dma_enable_mask corresponding to DMA2 (only 5 channels) + +// DMA1 streams +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, HAL_DMA1_CH3_DAC_CH1, DMA_MEMORY_TO_PERIPH, dma_id_3, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, HAL_DMA1_CH4_DAC_CH2, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, HAL_DMA1_CH5_SPI2_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c}; +const dma_descr_t dma_SPI_2_RX = { DMA1_Channel6, HAL_DMA1_CH6_SPI2_RX, DMA_PERIPH_TO_MEMORY, dma_id_6, &dma_init_struct_spi_i2c}; +const dma_descr_t dma_SPI_1_RX = { DMA2_Channel3, HAL_DMA2_CH3_SPI1_RX, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c}; +const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, HAL_DMA2_CH4_SPI1_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c}; + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Ch1_IRQn, + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch2_3_DMA2_Ch1_2_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + DMA1_Ch4_7_DMA2_Ch3_5_IRQn, + 0, + 0, +}; + +#elif defined(STM32F4) || defined(STM32F7) #define NCONTROLLERS (2) #define NSTREAMS_PER_CONTROLLER (8) @@ -161,7 +200,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = { // DMA1 streams const dma_descr_t dma_I2C_1_RX = { DMA1_Stream0, DMA_CHANNEL_1, DMA_PERIPH_TO_MEMORY, dma_id_0, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_3_RX = { DMA1_Stream2, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) const dma_descr_t dma_I2C_4_RX = { DMA1_Stream2, DMA_CHANNEL_2, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; #endif const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; @@ -169,7 +208,7 @@ const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_CHANNEL_7, DMA_PERIPH_TO_ME const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_CHANNEL_0, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, DMA_CHANNEL_2, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c }; #endif #if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC @@ -185,7 +224,7 @@ const dma_descr_t dma_I2C_1_TX = { DMA1_Stream6, DMA_CHANNEL_1, DMA_MEMORY_TO_PE */ // DMA2 streams -#if defined(MCU_SERIES_F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD const dma_descr_t dma_SDMMC_2_RX= { DMA2_Stream0, DMA_CHANNEL_11, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_sdio }; #endif const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_spi_i2c }; @@ -198,7 +237,7 @@ const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, DMA_MEMORY_TO_PE const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_CHANNEL_5, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, DMA_CHANNEL_1, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; -#if defined(MCU_SERIES_F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD const dma_descr_t dma_SDMMC_2_TX= { DMA2_Stream5, DMA_CHANNEL_11, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_sdio }; #endif const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, DMA_CHANNEL_1, DMA_PERIPH_TO_MEMORY, dma_id_14, &dma_init_struct_spi_i2c }; @@ -233,7 +272,7 @@ static const uint8_t dma_irqn[NSTREAM] = { DMA2_Stream7_IRQn, }; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) #define NCONTROLLERS (2) #define NSTREAMS_PER_CONTROLLER (7) @@ -308,6 +347,70 @@ static const uint8_t dma_irqn[NSTREAM] = { DMA2_Channel7_IRQn, }; +#elif defined(STM32H7) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (8) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (dma_channel) + +#define DMA1_ENABLE_MASK (0x00ff) // Bits in dma_enable_mask corresponding to DMA1 +#define DMA2_ENABLE_MASK (0xff00) // Bits in dma_enable_mask corresponding to DMA2 + +// These descriptors are ordered by DMAx_Stream number, and within a stream by channel +// number. The duplicate streams are ok as long as they aren't used at the same time. +// +// Currently I2C and SPI are synchronous and they call dma_init/dma_deinit +// around each transfer. + +// DMA1 streams +const dma_descr_t dma_I2C_1_RX = { DMA1_Stream0, DMA_REQUEST_I2C1_RX, DMA_PERIPH_TO_MEMORY, dma_id_0, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_3_RX = { DMA1_Stream2, DMA_REQUEST_SPI3_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_4_RX = { DMA1_Stream2, BDMA_REQUEST_I2C4_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_REQUEST_I2C3_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_REQUEST_I2C2_RX, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_REQUEST_SPI2_RX, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_REQUEST_SPI2_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_REQUEST_I2C3_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, BDMA_REQUEST_I2C4_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c }; +#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Stream5, DMA_REQUEST_DAC1_CH1, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_REQUEST_DAC1_CH2, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_3_TX = { DMA1_Stream7, DMA_REQUEST_SPI3_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_REQUEST_I2C1_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Stream7, DMA_REQUEST_I2C2_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; + +// DMA2 streams +const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_REQUEST_SPI1_RX, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_REQUEST_SPI5_RX, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_REQUEST_SPI4_RX, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_REQUEST_SPI5_TX, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_REQUEST_SPI4_TX, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, BDMA_REQUEST_SPI6_TX, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_REQUEST_SPI1_TX, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, BDMA_REQUEST_SPI6_RX, DMA_PERIPH_TO_MEMORY, dma_id_14, &dma_init_struct_spi_i2c }; + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Stream0_IRQn, + DMA1_Stream1_IRQn, + DMA1_Stream2_IRQn, + DMA1_Stream3_IRQn, + DMA1_Stream4_IRQn, + DMA1_Stream5_IRQn, + DMA1_Stream6_IRQn, + DMA1_Stream7_IRQn, + DMA2_Stream0_IRQn, + DMA2_Stream1_IRQn, + DMA2_Stream2_IRQn, + DMA2_Stream3_IRQn, + DMA2_Stream4_IRQn, + DMA2_Stream5_IRQn, + DMA2_Stream6_IRQn, + DMA2_Stream7_IRQn, +}; + #endif static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL}; @@ -317,10 +420,15 @@ volatile dma_idle_count_t dma_idle; #define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid +#if defined(STM32F0) +#define DMA1_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != 0) +#define DMA2_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA2EN) != 0) +#else #define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0) #define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0) +#endif -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) void DMA1_Stream0_IRQHandler(void) { IRQ_ENTER(DMA1_Stream0_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Stream0_IRQn); } void DMA1_Stream1_IRQHandler(void) { IRQ_ENTER(DMA1_Stream1_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Stream1_IRQn); } @@ -339,7 +447,7 @@ void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handl void DMA2_Stream6_IRQHandler(void) { IRQ_ENTER(DMA2_Stream6_IRQn); if (dma_handle[dma_id_14] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_14]); } IRQ_EXIT(DMA2_Stream6_IRQn); } void DMA2_Stream7_IRQHandler(void) { IRQ_ENTER(DMA2_Stream7_IRQn); if (dma_handle[dma_id_15] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_15]); } IRQ_EXIT(DMA2_Stream7_IRQn); } -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) void DMA1_Channel1_IRQHandler(void) { IRQ_ENTER(DMA1_Channel1_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Channel1_IRQn); } void DMA1_Channel2_IRQHandler(void) { IRQ_ENTER(DMA1_Channel2_IRQn); if (dma_handle[dma_id_1] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_1]); } IRQ_EXIT(DMA1_Channel2_IRQn); } @@ -373,7 +481,7 @@ static void dma_enable_clock(dma_id_t dma_id) { if (dma_id < NSTREAMS_PER_CONTROLLER) { if (((old_enable_mask & DMA1_ENABLE_MASK) == 0) && !DMA1_IS_CLK_ENABLED()) { - __DMA1_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); // We just turned on the clock. This means that anything stored // in dma_last_channel (for DMA1) needs to be invalidated. @@ -384,7 +492,7 @@ static void dma_enable_clock(dma_id_t dma_id) { } } else { if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) { - __DMA2_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); // We just turned on the clock. This means that anything stored // in dma_last_channel (for DMA1) needs to be invalidated. @@ -409,11 +517,13 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void dma->Instance = dma_descr->instance; dma->Init = *dma_descr->init; dma->Init.Direction = dma_descr->transfer_direction; - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) || defined(STM32H7) dma->Init.Request = dma_descr->sub_instance; #else + #if !defined(STM32F0) dma->Init.Channel = dma_descr->sub_instance; #endif + #endif // half of __HAL_LINKDMA(data, xxx, *dma) // caller must implement other half by doing: data->xxx = dma dma->Parent = data; @@ -434,6 +544,14 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ dma_enable_clock(dma_id); + #if defined(STM32L4) + // Always reset and configure the L4 DMA peripheral + // (dma->State is set to HAL_DMA_STATE_RESET by memset above) + // TODO: understand how L4 DMA works so this is not needed + HAL_DMA_DeInit(dma); + HAL_DMA_Init(dma); + NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA); + #else // if this stream was previously configured for this channel/request then we // can skip most of the initialisation uint8_t sub_inst = DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance); @@ -444,16 +562,24 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ // (dma->State is set to HAL_DMA_STATE_RESET by memset above) HAL_DMA_DeInit(dma); HAL_DMA_Init(dma); - HAL_NVIC_SetPriority(dma_irqn[dma_id], IRQ_PRI_DMA, IRQ_SUBPRI_DMA); + NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA); + #if defined(STM32F0) + if (dma->Instance < DMA2_Channel1) { + __HAL_DMA1_REMAP(dma_descr->sub_instance); + } else { + __HAL_DMA2_REMAP(dma_descr->sub_instance); + } + #endif } else { // only necessary initialization dma->State = HAL_DMA_STATE_READY; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) // calculate DMA base address and bitshift to be used in IRQ handler extern uint32_t DMA_CalcBaseAndBitshift(DMA_HandleTypeDef *hdma); DMA_CalcBaseAndBitshift(dma); #endif } + #endif HAL_NVIC_EnableIRQ(dma_irqn[dma_id]); } @@ -494,9 +620,9 @@ void dma_idle_handler(int tick) { // Now we'll really disable the clock. dma_idle.counter[controller] = 0; if (controller == 0) { - __DMA1_CLK_DISABLE(); + __HAL_RCC_DMA1_CLK_DISABLE(); } else { - __DMA2_CLK_DISABLE(); + __HAL_RCC_DMA2_CLK_DISABLE(); } } else { // Something is still active, but the counter never got diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 55fb621758..cacabe9253 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -23,12 +23,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_DMA_H -#define MICROPY_INCLUDED_STMHAL_DMA_H +#ifndef MICROPY_INCLUDED_STM32_DMA_H +#define MICROPY_INCLUDED_STM32_DMA_H typedef struct _dma_descr_t dma_descr_t; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) extern const dma_descr_t dma_I2C_1_RX; extern const dma_descr_t dma_SPI_3_RX; @@ -57,7 +57,7 @@ extern const dma_descr_t dma_SDMMC_2_TX; extern const dma_descr_t dma_SPI_6_RX; extern const dma_descr_t dma_SDIO_0_TX; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) extern const dma_descr_t dma_ADC_1_RX; extern const dma_descr_t dma_ADC_2_RX; @@ -100,4 +100,4 @@ void dma_deinit(const dma_descr_t *dma_descr); void dma_invalidate_channel(const dma_descr_t *dma_descr); void dma_idle_handler(int controller); -#endif // MICROPY_INCLUDED_STMHAL_DMA_H +#endif // MICROPY_INCLUDED_STM32_DMA_H diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index 41943f1cdb..70bf7eae7e 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -89,7 +89,7 @@ // register in an atomic fashion by using bitband addressing. #define EXTI_MODE_BB(mode, line) (*(__IO uint32_t *)(PERIPH_BB_BASE + ((EXTI_OFFSET + (mode)) * 32) + ((line) * 4))) -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) // The L4 MCU supports 40 Events/IRQs lines of the type configurable and direct. // Here we only support configurable line types. Details, see page 330 of RM0351, Rev 1. // The USB_FS_WAKUP event is a direct type and there is no support for it. @@ -97,6 +97,11 @@ #define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR1) #define EXTI_RTSR EXTI->RTSR1 #define EXTI_FTSR EXTI->FTSR1 +#elif defined(STM32H7) +#define EXTI_Mode_Interrupt offsetof(EXTI_Core_TypeDef, IMR1) +#define EXTI_Mode_Event offsetof(EXTI_Core_TypeDef, EMR1) +#define EXTI_RTSR EXTI->RTSR1 +#define EXTI_FTSR EXTI->FTSR1 #else #define EXTI_Mode_Interrupt offsetof(EXTI_TypeDef, IMR) #define EXTI_Mode_Event offsetof(EXTI_TypeDef, EMR) @@ -128,11 +133,17 @@ STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS]; #endif STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { + #if defined(STM32F0) + EXTI0_1_IRQn, EXTI0_1_IRQn, EXTI2_3_IRQn, EXTI2_3_IRQn, + EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, + EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, + EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, + #else EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) PVD_PVM_IRQn, #else PVD_IRQn, @@ -143,6 +154,7 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { OTG_HS_WKUP_IRQn, TAMP_STAMP_IRQn, RTC_WKUP_IRQn, + #endif }; // Set override_callback_obj to true if you want to unconditionally set the @@ -203,13 +215,13 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca exti.Pin = pin->pin_mask; exti.Mode = mode; exti.Pull = pull; - exti.Speed = GPIO_SPEED_FAST; + exti.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(pin->gpio, &exti); // Calling HAL_GPIO_Init does an implicit extint_enable /* Enable and set NVIC Interrupt to the lowest priority */ - HAL_NVIC_SetPriority(nvic_irq_channel[v_line], IRQ_PRI_EXTINT, IRQ_SUBPRI_EXTINT); + NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[v_line]), IRQ_PRI_EXTINT); HAL_NVIC_EnableIRQ(nvic_irq_channel[v_line]); } return v_line; @@ -265,7 +277,7 @@ void extint_register_pin(const pin_obj_t *pin, uint32_t mode, bool hard_irq, mp_ } // Configure the NVIC - HAL_NVIC_SetPriority(nvic_irq_channel[line], IRQ_PRI_EXTINT, IRQ_SUBPRI_EXTINT); + NVIC_SetPriority(IRQn_NONNEG(nvic_irq_channel[line]), IRQ_PRI_EXTINT); HAL_NVIC_EnableIRQ(nvic_irq_channel[line]); // Enable the interrupt @@ -277,13 +289,21 @@ void extint_enable(uint line) { if (line >= EXTI_NUM_VECTORS) { return; } - #if defined(MCU_SERIES_F7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) // The Cortex-M7 doesn't have bitband support. mp_uint_t irq_state = disable_irq(); if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) { + #if defined(STM32H7) + EXTI_D1->IMR1 |= (1 << line); + #else EXTI->IMR |= (1 << line); + #endif } else { + #if defined(STM32H7) + EXTI_D1->EMR1 |= (1 << line); + #else EXTI->EMR |= (1 << line); + #endif } enable_irq(irq_state); #else @@ -299,11 +319,16 @@ void extint_disable(uint line) { return; } - #if defined(MCU_SERIES_F7) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32H7) // The Cortex-M7 doesn't have bitband support. mp_uint_t irq_state = disable_irq(); + #if defined(STM32H7) + EXTI_D1->IMR1 &= ~(1 << line); + EXTI_D1->EMR1 &= ~(1 << line); + #else EXTI->IMR &= ~(1 << line); EXTI->EMR &= ~(1 << line); + #endif enable_irq(irq_state); #else // Since manipulating IMR/EMR is a read-modify-write, and we want this to @@ -319,7 +344,7 @@ void extint_swint(uint line) { return; } // we need 0 to 1 transition to trigger the interrupt -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) || defined(STM32H7) EXTI->SWIER1 &= ~(1 << line); EXTI->SWIER1 |= (1 << line); #else @@ -368,26 +393,45 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint); /// \classmethod regs() /// Dump the values of the EXTI registers. STATIC mp_obj_t extint_regs(void) { - #if defined(MCU_SERIES_L4) - printf("EXTI_IMR1 %08lx\n", EXTI->IMR1); - printf("EXTI_IMR2 %08lx\n", EXTI->IMR2); - printf("EXTI_EMR1 %08lx\n", EXTI->EMR1); - printf("EXTI_EMR2 %08lx\n", EXTI->EMR2); - printf("EXTI_RTSR1 %08lx\n", EXTI->RTSR1); - printf("EXTI_RTSR2 %08lx\n", EXTI->RTSR2); - printf("EXTI_FTSR1 %08lx\n", EXTI->FTSR1); - printf("EXTI_FTSR2 %08lx\n", EXTI->FTSR2); - printf("EXTI_SWIER1 %08lx\n", EXTI->SWIER1); - printf("EXTI_SWIER2 %08lx\n", EXTI->SWIER2); - printf("EXTI_PR1 %08lx\n", EXTI->PR1); - printf("EXTI_PR2 %08lx\n", EXTI->PR2); + #if defined(STM32L4) + printf("EXTI_IMR1 %08x\n", (unsigned int)EXTI->IMR1); + printf("EXTI_IMR2 %08x\n", (unsigned int)EXTI->IMR2); + printf("EXTI_EMR1 %08x\n", (unsigned int)EXTI->EMR1); + printf("EXTI_EMR2 %08x\n", (unsigned int)EXTI->EMR2); + printf("EXTI_RTSR1 %08x\n", (unsigned int)EXTI->RTSR1); + printf("EXTI_RTSR2 %08x\n", (unsigned int)EXTI->RTSR2); + printf("EXTI_FTSR1 %08x\n", (unsigned int)EXTI->FTSR1); + printf("EXTI_FTSR2 %08x\n", (unsigned int)EXTI->FTSR2); + printf("EXTI_SWIER1 %08x\n", (unsigned int)EXTI->SWIER1); + printf("EXTI_SWIER2 %08x\n", (unsigned int)EXTI->SWIER2); + printf("EXTI_PR1 %08x\n", (unsigned int)EXTI->PR1); + printf("EXTI_PR2 %08x\n", (unsigned int)EXTI->PR2); + #elif defined(STM32H7) + printf("EXTI_IMR1 %08x\n", (unsigned int)EXTI_D1->IMR1); + printf("EXTI_IMR2 %08x\n", (unsigned int)EXTI_D1->IMR2); + printf("EXTI_IMR3 %08x\n", (unsigned int)EXTI_D1->IMR3); + printf("EXTI_EMR1 %08x\n", (unsigned int)EXTI_D1->EMR1); + printf("EXTI_EMR2 %08x\n", (unsigned int)EXTI_D1->EMR2); + printf("EXTI_EMR3 %08x\n", (unsigned int)EXTI_D1->EMR3); + printf("EXTI_RTSR1 %08x\n", (unsigned int)EXTI->RTSR1); + printf("EXTI_RTSR2 %08x\n", (unsigned int)EXTI->RTSR2); + printf("EXTI_RTSR3 %08x\n", (unsigned int)EXTI->RTSR3); + printf("EXTI_FTSR1 %08x\n", (unsigned int)EXTI->FTSR1); + printf("EXTI_FTSR2 %08x\n", (unsigned int)EXTI->FTSR2); + printf("EXTI_FTSR3 %08x\n", (unsigned int)EXTI->FTSR3); + printf("EXTI_SWIER1 %08x\n", (unsigned int)EXTI->SWIER1); + printf("EXTI_SWIER2 %08x\n", (unsigned int)EXTI->SWIER2); + printf("EXTI_SWIER3 %08x\n", (unsigned int)EXTI->SWIER3); + printf("EXTI_PR1 %08x\n", (unsigned int)EXTI_D1->PR1); + printf("EXTI_PR2 %08x\n", (unsigned int)EXTI_D1->PR2); + printf("EXTI_PR3 %08x\n", (unsigned int)EXTI_D1->PR3); #else - printf("EXTI_IMR %08lx\n", EXTI->IMR); - printf("EXTI_EMR %08lx\n", EXTI->EMR); - printf("EXTI_RTSR %08lx\n", EXTI->RTSR); - printf("EXTI_FTSR %08lx\n", EXTI->FTSR); - printf("EXTI_SWIER %08lx\n", EXTI->SWIER); - printf("EXTI_PR %08lx\n", EXTI->PR); + printf("EXTI_IMR %08x\n", (unsigned int)EXTI->IMR); + printf("EXTI_EMR %08x\n", (unsigned int)EXTI->EMR); + printf("EXTI_RTSR %08x\n", (unsigned int)EXTI->RTSR); + printf("EXTI_FTSR %08x\n", (unsigned int)EXTI->FTSR); + printf("EXTI_SWIER %08x\n", (unsigned int)EXTI->SWIER); + printf("EXTI_PR %08x\n", (unsigned int)EXTI->PR); #endif return mp_const_none; } @@ -497,7 +541,7 @@ void Handle_EXTI_Irq(uint32_t line) { // Uncaught exception; disable the callback so it doesn't run again. *cb = mp_const_none; extint_disable(line); - printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line); + printf("Uncaught exception in ExtInt interrupt handler line %u\n", (unsigned int)line); mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); } gc_unlock(); diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h index 846790b9be..c4a4ae6bb9 100644 --- a/ports/stm32/extint.h +++ b/ports/stm32/extint.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_EXTINT_H -#define MICROPY_INCLUDED_STMHAL_EXTINT_H +#ifndef MICROPY_INCLUDED_STM32_EXTINT_H +#define MICROPY_INCLUDED_STM32_EXTINT_H // Vectors 0-15 are for regular pins // Vectors 16-22 are for internal sources. @@ -38,7 +38,7 @@ #define EXTI_USB_OTG_HS_WAKEUP (20) #define EXTI_RTC_TIMESTAMP (21) #define EXTI_RTC_WAKEUP (22) -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) #define EXTI_LPTIM1_ASYNC_EVENT (23) #endif @@ -64,4 +64,4 @@ void Handle_EXTI_Irq(uint32_t line); extern const mp_obj_type_t extint_type; -#endif // MICROPY_INCLUDED_STMHAL_EXTINT_H +#endif // MICROPY_INCLUDED_STM32_EXTINT_H diff --git a/ports/stm32/fatfs_port.c b/ports/stm32/fatfs_port.c index 17ec3f7266..d0e311ed77 100644 --- a/ports/stm32/fatfs_port.c +++ b/ports/stm32/fatfs_port.c @@ -32,7 +32,7 @@ DWORD get_fattime(void) { rtc_init_finalise(); RTC_TimeTypeDef time; RTC_DateTypeDef date; - HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); - HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); return ((2000 + date.Year - 1980) << 25) | ((date.Month) << 21) | ((date.Date) << 16) | ((time.Hours) << 11) | ((time.Minutes) << 5) | (time.Seconds / 2); } diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index bebb3a1619..26f76a1747 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -34,7 +34,13 @@ typedef struct { uint32_t sector_count; } flash_layout_t; -#if defined(MCU_SERIES_F4) +#if defined(STM32F0) + +static const flash_layout_t flash_layout[] = { + { FLASH_BASE, FLASH_PAGE_SIZE, (FLASH_BANK1_END + 1 - FLASH_BASE) / FLASH_PAGE_SIZE }, +}; + +#elif defined(STM32F4) static const flash_layout_t flash_layout[] = { { 0x08000000, 0x04000, 4 }, @@ -50,7 +56,7 @@ static const flash_layout_t flash_layout[] = { #endif }; -#elif defined(MCU_SERIES_F7) +#elif defined(STM32F7) // FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to // FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7 @@ -62,21 +68,31 @@ static const flash_layout_t flash_layout[] = { { 0x08040000, 0x40000, 3 }, }; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) static const flash_layout_t flash_layout[] = { { (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 }, }; +#elif defined(STM32H7) + +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x20000, 16 }, +}; + #else #error Unsupported processor #endif -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) || defined(STM32H7) // get the bank of a given flash address static uint32_t get_bank(uint32_t addr) { + #if defined(STM32H7) + if (READ_BIT(FLASH->OPTCR, FLASH_OPTCR_SWAP_BANK) == 0) { + #else if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0) { + #endif // no bank swap if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { return FLASH_BANK_1; @@ -93,6 +109,7 @@ static uint32_t get_bank(uint32_t addr) { } } +#if defined(STM32L4) // get the page of a given flash address static uint32_t get_page(uint32_t addr) { if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) { @@ -103,6 +120,7 @@ static uint32_t get_page(uint32_t addr) { return (addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE; } } +#endif #endif @@ -130,7 +148,7 @@ uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *si return 0; } -void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { +void flash_erase(uint32_t flash_dest, uint32_t num_word32) { // check there is something to write if (num_word32 == 0) { return; @@ -141,7 +159,12 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) FLASH_EraseInitTypeDef EraseInitStruct; - #if defined(MCU_SERIES_L4) + #if defined(STM32F0) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR); + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.PageAddress = flash_dest; + EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE; + #elif defined(STM32L4) __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); // erase the sector(s) @@ -153,12 +176,19 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) EraseInitStruct.NbPages = get_page(flash_dest + 4 * num_word32 - 1) - EraseInitStruct.Page + 1;; #else // Clear pending flags (if any) + #if defined(STM32H7) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS_BANK1 | FLASH_FLAG_ALL_ERRORS_BANK2); + #else __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); + #endif // erase the sector(s) EraseInitStruct.TypeErase = TYPEERASE_SECTORS; EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + #if defined(STM32H7) + EraseInitStruct.Banks = get_bank(flash_dest); + #endif EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL); EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1; #endif @@ -173,7 +203,7 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) /* // erase the sector using an interrupt -void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { +void flash_erase_it(uint32_t flash_dest, uint32_t num_word32) { // check there is something to write if (num_word32 == 0) { return; @@ -201,7 +231,7 @@ void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word3 */ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) // program the flash uint64 by uint64 for (int i = 0; i < num_word32 / 2; i++) { @@ -224,11 +254,24 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) } } + #elif defined(STM32H7) + + // program the flash 256 bits at a time + for (int i = 0; i < num_word32 / 8; i++) { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, flash_dest, (uint64_t)(uint32_t)src) != HAL_OK) { + // error occurred during flash write + HAL_FLASH_Lock(); // lock the flash + return; + } + flash_dest += 32; + src += 8; + } + #else // program the flash word by word for (int i = 0; i < num_word32; i++) { - if (HAL_FLASH_Program(TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) { // error occurred during flash write HAL_FLASH_Lock(); // lock the flash return; diff --git a/ports/stm32/flash.h b/ports/stm32/flash.h index 688e70a3cd..b9edf61061 100644 --- a/ports/stm32/flash.h +++ b/ports/stm32/flash.h @@ -23,11 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_FLASH_H -#define MICROPY_INCLUDED_STMHAL_FLASH_H +#ifndef MICROPY_INCLUDED_STM32_FLASH_H +#define MICROPY_INCLUDED_STM32_FLASH_H uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size); -void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); +void flash_erase(uint32_t flash_dest, uint32_t num_word32); void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); -#endif // MICROPY_INCLUDED_STMHAL_FLASH_H +#endif // MICROPY_INCLUDED_STM32_FLASH_H diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c new file mode 100644 index 0000000000..5ae67d1ec2 --- /dev/null +++ b/ports/stm32/flashbdev.c @@ -0,0 +1,269 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/mperrno.h" +#include "led.h" +#include "flash.h" +#include "storage.h" + +#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE + +// Here we try to automatically configure the location and size of the flash +// pages to use for the internal storage. We also configure the location of the +// cache used for writing. + +#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k + +// enable this to get an extra 64k of storage (uses the last sector of the flash) +#if 0 +#define FLASH_MEM_SEG2_START_ADDR (0x080e0000) // sector 11 +#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 11: 128k +#endif + +#elif defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) + +STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k +#define CACHE_MEM_START_ADDR (&flash_cache_mem[0]) +#define FLASH_SECTOR_SIZE_MAX (0x4000) // 16k max due to size of cache buffer +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (128) // sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k + +#elif defined(STM32F429xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM +#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k + +#elif defined(STM32F439xx) + +#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM +#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12 +#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k +#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18 +#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k) + +#elif defined(STM32F746xx) || defined(STM32F767xx) || defined(STM32F769xx) + +// The STM32F746 doesn't really have CCRAM, so we use the 64K DTCM for this. + +#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k +#define FLASH_SECTOR_SIZE_MAX (0x08000) // 32k max +#define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k + +#elif defined(STM32H743xx) + +// The STM32H743 flash sectors are 128K +#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 128k +#define FLASH_SECTOR_SIZE_MAX (0x20000) // 128k max +#define FLASH_MEM_SEG1_START_ADDR (0x08020000) // sector 1 +#define FLASH_MEM_SEG1_NUM_BLOCKS (256) // Sector 1: 128k / 512b = 256 blocks + +#elif defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L496xx) + +extern uint8_t _flash_fs_start; +extern uint8_t _flash_fs_end; +extern uint32_t _ram_fs_cache_start[2048 / 4]; +extern uint32_t _ram_fs_cache_block_size; + +// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this. +#define CACHE_MEM_START_ADDR (&_ram_fs_cache_start) // End of SRAM2 RAM segment-2k +#define FLASH_SECTOR_SIZE_MAX (_ram_fs_cache_block_size) // 2k max +#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start) +#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512) + +#else +#error "no internal flash storage support for this MCU" +#endif + +#if !defined(FLASH_MEM_SEG2_START_ADDR) +#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment +#define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment +#endif + +#define FLASH_FLAG_DIRTY (1) +#define FLASH_FLAG_FORCE_WRITE (2) +#define FLASH_FLAG_ERASED (4) +static __IO uint8_t flash_flags = 0; +static uint32_t flash_cache_sector_id; +static uint32_t flash_cache_sector_start; +static uint32_t flash_cache_sector_size; +static uint32_t flash_tick_counter_last_write; + +static void flash_bdev_irq_handler(void); + +int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg) { + (void)arg; + switch (op) { + case BDEV_IOCTL_INIT: + flash_flags = 0; + flash_cache_sector_id = 0; + flash_tick_counter_last_write = 0; + return 0; + + case BDEV_IOCTL_NUM_BLOCKS: + return FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS; + + case BDEV_IOCTL_IRQ_HANDLER: + flash_bdev_irq_handler(); + return 0; + + case BDEV_IOCTL_SYNC: + if (flash_flags & FLASH_FLAG_DIRTY) { + flash_flags |= FLASH_FLAG_FORCE_WRITE; + while (flash_flags & FLASH_FLAG_DIRTY) { + NVIC->STIR = FLASH_IRQn; + } + } + return 0; + } + return -MP_EINVAL; +} + +static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) { + uint32_t flash_sector_start; + uint32_t flash_sector_size; + uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); + if (flash_sector_size > FLASH_SECTOR_SIZE_MAX) { + flash_sector_size = FLASH_SECTOR_SIZE_MAX; + } + if (flash_cache_sector_id != flash_sector_id) { + flash_bdev_ioctl(BDEV_IOCTL_SYNC, 0); + memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size); + flash_cache_sector_id = flash_sector_id; + flash_cache_sector_start = flash_sector_start; + flash_cache_sector_size = flash_sector_size; + } + flash_flags |= FLASH_FLAG_DIRTY; + led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on + flash_tick_counter_last_write = HAL_GetTick(); + return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; +} + +static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) { + uint32_t flash_sector_start; + uint32_t flash_sector_size; + uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); + if (flash_cache_sector_id == flash_sector_id) { + // in cache, copy from there + return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; + } + // not in cache, copy straight from flash + return (uint8_t*)flash_addr; +} + +static uint32_t convert_block_to_flash_addr(uint32_t block) { + if (block < FLASH_MEM_SEG1_NUM_BLOCKS) { + return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE; + } + if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) { + return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE; + } + // can add more flash segments here if needed, following above pattern + + // bad block + return -1; +} + +static void flash_bdev_irq_handler(void) { + if (!(flash_flags & FLASH_FLAG_DIRTY)) { + return; + } + + // This code uses interrupts to erase the flash + /* + if (flash_erase_state == 0) { + flash_erase_it(flash_cache_sector_start, flash_cache_sector_size / 4); + flash_erase_state = 1; + return; + } + + if (flash_erase_state == 1) { + // wait for erase + // TODO add timeout + #define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET) + if (!flash_erase_done()) { + return; + } + flash_erase_state = 2; + } + */ + + // This code erases the flash directly, waiting for it to finish + if (!(flash_flags & FLASH_FLAG_ERASED)) { + flash_erase(flash_cache_sector_start, flash_cache_sector_size / 4); + flash_flags |= FLASH_FLAG_ERASED; + return; + } + + // If not a forced write, wait at least 5 seconds after last write to flush + // On file close and flash unmount we get a forced write, so we can afford to wait a while + if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || HAL_GetTick() - flash_tick_counter_last_write >= 5000) { + // sync the cache RAM buffer by writing it to the flash page + flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + // clear the flash flags now that we have a clean cache + flash_flags = 0; + // indicate a clean cache with LED off + led_state(PYB_LED_RED, 0); + } +} + +bool flash_bdev_readblock(uint8_t *dest, uint32_t block) { + // non-MBR block, get data from flash memory, possibly via cache + uint32_t flash_addr = convert_block_to_flash_addr(block); + if (flash_addr == -1) { + // bad block number + return false; + } + uint8_t *src = flash_cache_get_addr_for_read(flash_addr); + memcpy(dest, src, FLASH_BLOCK_SIZE); + return true; +} + +bool flash_bdev_writeblock(const uint8_t *src, uint32_t block) { + // non-MBR block, copy to cache + uint32_t flash_addr = convert_block_to_flash_addr(block); + if (flash_addr == -1) { + // bad block number + return false; + } + uint8_t *dest = flash_cache_get_addr_for_write(flash_addr); + memcpy(dest, src, FLASH_BLOCK_SIZE); + return true; +} + +#endif // MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE diff --git a/ports/stm32/font_petme128_8x8.h b/ports/stm32/font_petme128_8x8.h index 8b0cc9cb01..cdc4e73a79 100644 --- a/ports/stm32/font_petme128_8x8.h +++ b/ports/stm32/font_petme128_8x8.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H -#define MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H +#ifndef MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H +#define MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H static const uint8_t font_petme128_8x8[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32= @@ -125,4 +125,4 @@ static const uint8_t font_petme128_8x8[] = { 0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55, // 127 }; -#endif // MICROPY_INCLUDED_STMHAL_FONT_PETME128_8X8_H +#endif // MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H diff --git a/ports/stm32/gccollect.h b/ports/stm32/gccollect.h index 1b64a51a6a..25a74a306a 100644 --- a/ports/stm32/gccollect.h +++ b/ports/stm32/gccollect.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_GCCOLLECT_H -#define MICROPY_INCLUDED_STMHAL_GCCOLLECT_H +#ifndef MICROPY_INCLUDED_STM32_GCCOLLECT_H +#define MICROPY_INCLUDED_STM32_GCCOLLECT_H // variables defining memory layout // (these probably belong somewhere else...) @@ -40,4 +40,4 @@ extern uint32_t _heap_end; extern uint32_t _estack; extern uint32_t _ram_end; -#endif // MICROPY_INCLUDED_STMHAL_GCCOLLECT_H +#endif // MICROPY_INCLUDED_STM32_GCCOLLECT_H diff --git a/ports/stm32/gchelper_m0.s b/ports/stm32/gchelper_m0.s new file mode 100644 index 0000000000..db0d9738d1 --- /dev/null +++ b/ports/stm32/gchelper_m0.s @@ -0,0 +1,61 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m0 + .thumb + + .section .text + .align 2 + + .global gc_helper_get_regs_and_sp + .type gc_helper_get_regs_and_sp, %function + +@ uint gc_helper_get_regs_and_sp(r0=uint regs[10]) +gc_helper_get_regs_and_sp: + @ store registers into given array + str r4, [r0, #0] + str r5, [r0, #4] + str r6, [r0, #8] + str r7, [r0, #12] + mov r1, r8 + str r1, [r0, #16] + mov r1, r9 + str r1, [r0, #20] + mov r1, r10 + str r1, [r0, #24] + mov r1, r11 + str r1, [r0, #28] + mov r1, r12 + str r1, [r0, #32] + mov r1, r13 + str r1, [r0, #36] + + @ return the sp + mov r0, sp + bx lr + + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index b22787cab5..109b9418f8 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,1012 +24,451 @@ * THE SOFTWARE. */ -#include -#include - -#include "py/runtime.h" +#include "py/mperrno.h" #include "py/mphal.h" -#include "irq.h" -#include "pin.h" -#include "genhdr/pins.h" -#include "bufhelper.h" -#include "dma.h" #include "i2c.h" -/// \moduleref pyb -/// \class I2C - a two-wire serial protocol -/// -/// I2C is a two-wire protocol for communicating between devices. At the physical -/// level it consists of 2 wires: SCL and SDA, the clock and data lines respectively. -/// -/// I2C objects are created attached to a specific bus. They can be initialised -/// when created, or initialised later on: -/// -/// from pyb import I2C -/// -/// i2c = I2C(1) # create on bus 1 -/// i2c = I2C(1, I2C.MASTER) # create and init as a master -/// i2c.init(I2C.MASTER, baudrate=20000) # init as a master -/// i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address -/// i2c.deinit() # turn off the peripheral -/// -/// Printing the i2c object gives you information about its configuration. -/// -/// Basic methods for slave are send and recv: -/// -/// i2c.send('abc') # send 3 bytes -/// i2c.send(0x42) # send a single byte, given by the number -/// data = i2c.recv(3) # receive 3 bytes -/// -/// To receive inplace, first create a bytearray: -/// -/// data = bytearray(3) # create a buffer -/// i2c.recv(data) # receive 3 bytes, writing them into data -/// -/// You can specify a timeout (in ms): -/// -/// i2c.send(b'123', timeout=2000) # timout after 2 seconds -/// -/// A master must specify the recipient's address: -/// -/// i2c.init(I2C.MASTER) -/// i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42 -/// i2c.send(b'456', addr=0x42) # keyword for address -/// -/// Master also has other methods: -/// -/// i2c.is_ready(0x42) # check if slave 0x42 is ready -/// i2c.scan() # scan for slaves on the bus, returning -/// # a list of valid addresses -/// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42, -/// # starting at address 2 in the slave -/// i2c.mem_write('abc', 0x42, 2, timeout=1000) -#define PYB_I2C_MASTER (0) -#define PYB_I2C_SLAVE (1) +#if MICROPY_HW_ENABLE_HW_I2C -#if defined(MICROPY_HW_I2C1_SCL) -I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL}; -#endif -#if defined(MICROPY_HW_I2C2_SCL) -I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL}; -#endif -#if defined(MICROPY_HW_I2C3_SCL) -I2C_HandleTypeDef I2CHandle3 = {.Instance = NULL}; -#endif -#if defined(MICROPY_HW_I2C4_SCL) -I2C_HandleTypeDef I2CHandle4 = {.Instance = NULL}; -#endif +#define I2C_POLL_TIMEOUT_MS (50) -STATIC bool pyb_i2c_use_dma[4]; +#if defined(STM32F4) -const pyb_i2c_obj_t pyb_i2c_obj[] = { - #if defined(MICROPY_HW_I2C1_SCL) - {{&pyb_i2c_type}, &I2CHandle1, &dma_I2C_1_TX, &dma_I2C_1_RX, &pyb_i2c_use_dma[0]}, - #else - {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, - #endif - #if defined(MICROPY_HW_I2C2_SCL) - {{&pyb_i2c_type}, &I2CHandle2, &dma_I2C_2_TX, &dma_I2C_2_RX, &pyb_i2c_use_dma[1]}, - #else - {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, - #endif - #if defined(MICROPY_HW_I2C3_SCL) - {{&pyb_i2c_type}, &I2CHandle3, &dma_I2C_3_TX, &dma_I2C_3_RX, &pyb_i2c_use_dma[2]}, - #else - {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, - #endif - #if defined(MICROPY_HW_I2C4_SCL) - {{&pyb_i2c_type}, &I2CHandle4, &dma_I2C_4_TX, &dma_I2C_4_RX, &pyb_i2c_use_dma[3]}, - #else - {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, - #endif -}; +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) - -// The STM32F0, F3, F7 and L4 use a TIMINGR register rather than ClockSpeed and -// DutyCycle. - -#if defined(STM32F746xx) - -// The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant -// defined in the STM32F7Cube file Drivers/BSP/STM32F746G-Discovery/stm32f7456g_discovery.h -#define MICROPY_HW_I2C_BAUDRATE_TIMING {{100000, 0x40912732}} -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (100000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (100000) - -#elif defined(STM32F767xx) || defined(STM32F769xx) - -// These timing values are for f_I2CCLK=54MHz and are only approximate -#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ - {100000, 0xb0420f13}, \ - {400000, 0x70330309}, \ - {1000000, 0x50100103}, \ + // Init pins + if (!mp_hal_pin_config_alt(scl, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; } -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (1000000) - -#elif defined(MCU_SERIES_L4) - -// The value 0x90112626 was obtained from the DISCOVERY_I2C1_TIMING constant -// defined in the STM32L4Cube file Drivers/BSP/STM32L476G-Discovery/stm32l476g_discovery.h -#define MICROPY_HW_I2C_BAUDRATE_TIMING {{100000, 0x90112626}} -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (100000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (100000) - -#else -#error "no I2C timings for this MCU" -#endif - -STATIC const struct { - uint32_t baudrate; - uint32_t timing; -} pyb_i2c_baudrate_timing[] = MICROPY_HW_I2C_BAUDRATE_TIMING; - -#define NUM_BAUDRATE_TIMINGS MP_ARRAY_SIZE(pyb_i2c_baudrate_timing) - -STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { - for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) { - if (pyb_i2c_baudrate_timing[i].baudrate == baudrate) { - init->Timing = pyb_i2c_baudrate_timing[i].timing; - return; - } + if (!mp_hal_pin_config_alt(sda, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Unsupported I2C baudrate: %lu", baudrate)); + + // Force reset I2C peripheral + RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST << i2c_id; + RCC->APB1RSTR &= ~(RCC_APB1RSTR_I2C1RST << i2c_id); + + // Enable I2C peripheral clock + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN << i2c_id; + volatile uint32_t tmp = RCC->APB1ENR; // delay after RCC clock enable + (void)tmp; + + uint32_t PCLK1 = HAL_RCC_GetPCLK1Freq(); + + // Initialise I2C peripheral + i2c->CR1 = 0; + i2c->CR2 = PCLK1 / 1000000; + i2c->OAR1 = 0; + i2c->OAR2 = 0; + + freq = MIN(freq, 400000); + + // SM: MAX(4, PCLK1 / (F * 2)) + // FM, 16:9 duty: 0xc000 | MAX(1, (PCLK1 / (F * (16 + 9)))) + if (freq <= 100000) { + i2c->CCR = MAX(4, PCLK1 / (freq * 2)); + } else { + i2c->CCR = 0xc000 | MAX(1, PCLK1 / (freq * 25)); + } + + // SM: 1000ns / (1/PCLK1) + 1 = PCLK1 * 1e-6 + 1 + // FM: 300ns / (1/PCLK1) + 1 = 300e-3 * PCLK1 * 1e-6 + 1 + if (freq <= 100000) { + i2c->TRISE = PCLK1 / 1000000 + 1; // 1000ns rise time in SM + } else { + i2c->TRISE = PCLK1 / 1000000 * 3 / 10 + 1; // 300ns rise time in FM + } + + #if defined(I2C_FLTR_ANOFF) + i2c->FLTR = 0; // analog filter on, digital filter off + #endif + + return 0; } -uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) { - for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) { - if (pyb_i2c_baudrate_timing[i].timing == init->Timing) { - return pyb_i2c_baudrate_timing[i].baudrate; +STATIC int i2c_wait_sr1_set(i2c_t *i2c, uint32_t mask) { + uint32_t t0 = HAL_GetTick(); + while (!(i2c->SR1 & mask)) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; } } return 0; } -#else - -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (400000) - -STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { - init->ClockSpeed = baudrate; - init->DutyCycle = I2C_DUTYCYCLE_16_9; +STATIC int i2c_wait_stop(i2c_t *i2c) { + uint32_t t0 = HAL_GetTick(); + while (i2c->CR1 & I2C_CR1_STOP) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + i2c->CR1 &= ~I2C_CR1_PE; + return 0; } -uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) { - return init->ClockSpeed; +// For write: len = 0, 1 or N +// For read: len = 1, 2 or N; stop = true +int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t next_len, bool stop) { + if (!(i2c->CR1 & I2C_CR1_PE) && (i2c->SR2 & I2C_SR2_MSL)) { + // The F4 I2C peripheral can sometimes get into a bad state where it's disabled + // (PE low) but still an active master (MSL high). It seems the best way to get + // out of this is a full reset. + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST << i2c_id; + RCC->APB1RSTR &= ~(RCC_APB1RSTR_I2C1RST << i2c_id); + } + + // It looks like it's possible to terminate the reading by sending a + // START condition instead of STOP condition but we don't support that. + if (rd_wrn) { + if (!stop) { + return -MP_EINVAL; + } + } + + // Repurpose OAR1 to hold stop flag + i2c->OAR1 = stop; + + // Enable peripheral and send START condition + i2c->CR1 |= I2C_CR1_PE; + i2c->CR1 |= I2C_CR1_START; + + // Wait for START to be sent + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_SB))) { + return ret; + } + + // Send the 7-bit address with read/write bit + i2c->DR = addr << 1 | rd_wrn; + + // Wait for address to be sent + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_ADDR))) { + return ret; + } + + // Check if the slave responded or not + if (i2c->SR1 & I2C_SR1_AF) { + // Got a NACK + i2c->CR1 |= I2C_CR1_STOP; + i2c_wait_stop(i2c); // Don't leak errors from this call + return -MP_ENODEV; + } + + if (rd_wrn) { + // For reading, set up ACK/NACK control based on number of bytes to read (at least 1 byte) + if (next_len <= 1) { + // NACK next received byte + i2c->CR1 &= ~I2C_CR1_ACK; + } else if (next_len <= 2) { + // NACK second received byte + i2c->CR1 |= I2C_CR1_POS; + i2c->CR1 &= ~I2C_CR1_ACK; + } else { + // ACK next received byte + i2c->CR1 |= I2C_CR1_ACK; + } + } + + // Read SR2 to clear SR1_ADDR + uint32_t sr2 = i2c->SR2; + (void)sr2; + + return 0; +} + +// next_len = 0 or N (>=2) +int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len) { + if (len == 0) { + return -MP_EINVAL; + } + if (next_len == 1) { + return -MP_EINVAL; + } + + size_t remain = len + next_len; + if (remain == 1) { + // Special case + i2c->CR1 |= I2C_CR1_STOP; + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_RXNE))) { + return ret; + } + *dest = i2c->DR; + } else { + for (; len; --len) { + remain = len + next_len; + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_BTF))) { + return ret; + } + if (remain == 2) { + // In this case next_len == 0 (it's not allowed to be 1) + i2c->CR1 |= I2C_CR1_STOP; + *dest++ = i2c->DR; + *dest = i2c->DR; + break; + } else if (remain == 3) { + // NACK next received byte + i2c->CR1 &= ~I2C_CR1_ACK; + } + *dest++ = i2c->DR; + } + } + + if (!next_len) { + // We sent a stop above, just wait for it to be finished + return i2c_wait_stop(i2c); + } + + return 0; +} + +// next_len = 0 or N +int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { + int ret; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_TXE))) { + return ret; + } + + // Write out the data + int num_acks = 0; + while (len--) { + i2c->DR = *src++; + if ((ret = i2c_wait_sr1_set(i2c, I2C_SR1_AF | I2C_SR1_BTF))) { + return ret; + } + if (i2c->SR1 & I2C_SR1_AF) { + // Slave did not respond to byte so stop sending + break; + } + ++num_acks; + } + + if (!next_len) { + if (i2c->OAR1) { + // Send a STOP and wait for it to finish + i2c->CR1 |= I2C_CR1_STOP; + if ((ret = i2c_wait_stop(i2c))) { + return ret; + } + } + } + + return num_acks; +} + +#elif defined(STM32F0) || defined(STM32F7) + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) { + uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + + // Init pins + if (!mp_hal_pin_config_alt(scl, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + if (!mp_hal_pin_config_alt(sda, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_UP, AF_FN_I2C, i2c_id + 1)) { + return -MP_EPERM; + } + + // Enable I2C peripheral clock + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN << i2c_id; + volatile uint32_t tmp = RCC->APB1ENR; // delay after RCC clock enable + (void)tmp; + + // Initialise I2C peripheral + i2c->CR1 = 0; + i2c->CR2 = 0; + i2c->OAR1 = 0; + i2c->OAR2 = 0; + + // These timing values are for f_I2CCLK=54MHz and are only approximate + if (freq >= 1000000) { + i2c->TIMINGR = 0x50100103; + } else if (freq >= 400000) { + i2c->TIMINGR = 0x70330309; + } else if (freq >= 100000) { + i2c->TIMINGR = 0xb0420f13; + } else { + return -MP_EINVAL; + } + + i2c->TIMEOUTR = 0; + + return 0; +} + +STATIC int i2c_wait_cr2_clear(i2c_t *i2c, uint32_t mask) { + uint32_t t0 = HAL_GetTick(); + while (i2c->CR2 & mask) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + return 0; +} + +STATIC int i2c_wait_isr_set(i2c_t *i2c, uint32_t mask) { + uint32_t t0 = HAL_GetTick(); + while (!(i2c->ISR & mask)) { + if (HAL_GetTick() - t0 >= I2C_POLL_TIMEOUT_MS) { + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ETIMEDOUT; + } + } + return 0; +} + +// len = 0, 1 or N +int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop) { + // Enable the peripheral and send the START condition with slave address + i2c->CR1 |= I2C_CR1_PE; + i2c->CR2 = stop << I2C_CR2_AUTOEND_Pos + | (len > 1) << I2C_CR2_RELOAD_Pos + | (len > 0) << I2C_CR2_NBYTES_Pos + | rd_wrn << I2C_CR2_RD_WRN_Pos + | (addr & 0x7f) << 1; + i2c->CR2 |= I2C_CR2_START; + + // Wait for address to be sent + int ret; + if ((ret = i2c_wait_cr2_clear(i2c, I2C_CR2_START))) { + return ret; + } + + // Check if the slave responded or not + if (i2c->ISR & I2C_ISR_NACKF) { + // If we get a NACK then I2C periph unconditionally sends a STOP + i2c_wait_isr_set(i2c, I2C_ISR_STOPF); // Don't leak errors from this call + i2c->CR1 &= ~I2C_CR1_PE; + return -MP_ENODEV; + } + + // Repurpose OAR1 to indicate that we loaded CR2 + i2c->OAR1 = 1; + + return 0; +} + +STATIC int i2c_check_stop(i2c_t *i2c) { + if (i2c->CR2 & I2C_CR2_AUTOEND) { + // Wait for the STOP condition and then disable the peripheral + int ret; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_STOPF))) { + return ret; + } + i2c->CR1 &= ~I2C_CR1_PE; + } + + return 0; +} + +// next_len = 0 or N +int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len) { + if (i2c->OAR1) { + i2c->OAR1 = 0; + } else { + goto load_cr2; + } + + // Read in the data + while (len--) { + int ret; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_RXNE))) { + return ret; + } + *dest++ = i2c->RXDR; + load_cr2: + if (len) { + i2c->CR2 = (i2c->CR2 & I2C_CR2_AUTOEND) + | (len + next_len > 1) << I2C_CR2_RELOAD_Pos + | 1 << I2C_CR2_NBYTES_Pos; + } + } + + if (!next_len) { + int ret; + if ((ret = i2c_check_stop(i2c))) { + return ret; + } + } + + return 0; +} + +// next_len = 0 or N +int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) { + int num_acks = 0; + + if (i2c->OAR1) { + i2c->OAR1 = 0; + } else { + goto load_cr2; + } + + // Write out the data + while (len--) { + int ret; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_TXE))) { + return ret; + } + i2c->TXDR = *src++; + if ((ret = i2c_wait_isr_set(i2c, I2C_ISR_TCR | I2C_ISR_TC | I2C_ISR_STOPF))) { + return ret; + } + uint32_t isr = i2c->ISR; + if (isr & I2C_ISR_NACKF) { + // Slave did not respond to byte so stop sending + if (!(isr & I2C_ISR_TXE)) { + // The TXDR is still full so the byte previous to that wasn't actually ACK'd + --num_acks; + } + break; + } + ++num_acks; + load_cr2: + if (len) { + i2c->CR2 = (i2c->CR2 & I2C_CR2_AUTOEND) + | (len + next_len > 1) << I2C_CR2_RELOAD_Pos + | 1 << I2C_CR2_NBYTES_Pos; + } + } + + if (!next_len) { + int ret; + if ((ret = i2c_check_stop(i2c))) { + return ret; + } + } + + return num_acks; } #endif -void i2c_init0(void) { - // reset the I2C1 handles - #if defined(MICROPY_HW_I2C1_SCL) - memset(&I2CHandle1, 0, sizeof(I2C_HandleTypeDef)); - I2CHandle1.Instance = I2C1; - #endif - #if defined(MICROPY_HW_I2C2_SCL) - memset(&I2CHandle2, 0, sizeof(I2C_HandleTypeDef)); - I2CHandle2.Instance = I2C2; - #endif - #if defined(MICROPY_HW_I2C3_SCL) - memset(&I2CHandle3, 0, sizeof(I2C_HandleTypeDef)); - I2CHandle3.Instance = I2C3; - #endif - #if defined(MICROPY_HW_I2C4_SCL) - memset(&I2CHandle4, 0, sizeof(I2C_HandleTypeDef)); - I2CHandle3.Instance = I2C4; - #endif +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) + +int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + int ret; + if ((ret = i2c_start_addr(i2c, 1, addr, len, stop))) { + return ret; + } + return i2c_read(i2c, dest, len, 0); } -void i2c_init(I2C_HandleTypeDef *i2c) { - int i2c_unit; - const pin_obj_t *scl_pin; - const pin_obj_t *sda_pin; - - if (0) { - #if defined(MICROPY_HW_I2C1_SCL) - } else if (i2c == &I2CHandle1) { - i2c_unit = 1; - scl_pin = &MICROPY_HW_I2C1_SCL; - sda_pin = &MICROPY_HW_I2C1_SDA; - __I2C1_CLK_ENABLE(); - #endif - #if defined(MICROPY_HW_I2C2_SCL) - } else if (i2c == &I2CHandle2) { - i2c_unit = 2; - scl_pin = &MICROPY_HW_I2C2_SCL; - sda_pin = &MICROPY_HW_I2C2_SDA; - __I2C2_CLK_ENABLE(); - #endif - #if defined(MICROPY_HW_I2C3_SCL) - } else if (i2c == &I2CHandle3) { - i2c_unit = 3; - scl_pin = &MICROPY_HW_I2C3_SCL; - sda_pin = &MICROPY_HW_I2C3_SDA; - __I2C3_CLK_ENABLE(); - #endif - #if defined(MICROPY_HW_I2C4_SCL) - } else if (i2c == &I2CHandle4) { - i2c_unit = 4; - scl_pin = &MICROPY_HW_I2C4_SCL; - sda_pin = &MICROPY_HW_I2C4_SDA; - __I2C3_CLK_ENABLE(); - #endif - } else { - // I2C does not exist for this board (shouldn't get here, should be checked by caller) - return; - } - - // init the GPIO lines - uint32_t mode = MP_HAL_PIN_MODE_ALT_OPEN_DRAIN; - uint32_t pull = MP_HAL_PIN_PULL_NONE; // have external pull-up resistors on both lines - mp_hal_pin_config_alt(scl_pin, mode, pull, AF_FN_I2C, i2c_unit); - mp_hal_pin_config_alt(sda_pin, mode, pull, AF_FN_I2C, i2c_unit); - - // init the I2C device - if (HAL_I2C_Init(i2c) != HAL_OK) { - // init error - // TODO should raise an exception, but this function is not necessarily going to be - // called via Python, so may not be properly wrapped in an NLR handler - printf("OSError: HAL_I2C_Init failed\n"); - return; - } - - // invalidate the DMA channels so they are initialised on first use - const pyb_i2c_obj_t *self = &pyb_i2c_obj[i2c_unit - 1]; - dma_invalidate_channel(self->tx_dma_descr); - dma_invalidate_channel(self->rx_dma_descr); - - if (0) { - #if defined(MICROPY_HW_I2C1_SCL) - } else if (i2c->Instance == I2C1) { - HAL_NVIC_EnableIRQ(I2C1_EV_IRQn); - HAL_NVIC_EnableIRQ(I2C1_ER_IRQn); - #endif - #if defined(MICROPY_HW_I2C2_SCL) - } else if (i2c->Instance == I2C2) { - HAL_NVIC_EnableIRQ(I2C2_EV_IRQn); - HAL_NVIC_EnableIRQ(I2C2_ER_IRQn); - #endif - #if defined(MICROPY_HW_I2C3_SCL) - } else if (i2c->Instance == I2C3) { - HAL_NVIC_EnableIRQ(I2C3_EV_IRQn); - HAL_NVIC_EnableIRQ(I2C3_ER_IRQn); - #endif - #if defined(MICROPY_HW_I2C4_SCL) - } else if (i2c->Instance == I2C4) { - HAL_NVIC_EnableIRQ(I2C4_EV_IRQn); - HAL_NVIC_EnableIRQ(I2C4_ER_IRQn); - #endif +int i2c_writeto(i2c_t *i2c, uint16_t addr, const uint8_t *src, size_t len, bool stop) { + int ret; + if ((ret = i2c_start_addr(i2c, 0, addr, len, stop))) { + return ret; } + return i2c_write(i2c, src, len, 0); } -void i2c_deinit(I2C_HandleTypeDef *i2c) { - HAL_I2C_DeInit(i2c); - if (0) { - #if defined(MICROPY_HW_I2C1_SCL) - } else if (i2c->Instance == I2C1) { - __I2C1_FORCE_RESET(); - __I2C1_RELEASE_RESET(); - __I2C1_CLK_DISABLE(); - HAL_NVIC_DisableIRQ(I2C1_EV_IRQn); - HAL_NVIC_DisableIRQ(I2C1_ER_IRQn); - #endif - #if defined(MICROPY_HW_I2C2_SCL) - } else if (i2c->Instance == I2C2) { - __I2C2_FORCE_RESET(); - __I2C2_RELEASE_RESET(); - __I2C2_CLK_DISABLE(); - HAL_NVIC_DisableIRQ(I2C2_EV_IRQn); - HAL_NVIC_DisableIRQ(I2C2_ER_IRQn); - #endif - #if defined(MICROPY_HW_I2C3_SCL) - } else if (i2c->Instance == I2C3) { - __I2C3_FORCE_RESET(); - __I2C3_RELEASE_RESET(); - __I2C3_CLK_DISABLE(); - HAL_NVIC_DisableIRQ(I2C3_EV_IRQn); - HAL_NVIC_DisableIRQ(I2C3_ER_IRQn); - #endif - #if defined(MICROPY_HW_I2C4_SCL) - } else if (i2c->Instance == I2C4) { - __HAL_RCC_I2C4_FORCE_RESET(); - __HAL_RCC_I2C4_RELEASE_RESET(); - __HAL_RCC_I2C4_CLK_DISABLE(); - HAL_NVIC_DisableIRQ(I2C4_EV_IRQn); - HAL_NVIC_DisableIRQ(I2C4_ER_IRQn); - #endif - } -} +#endif -void i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq) { - I2C_InitTypeDef *init = &self->i2c->Init; - - init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; - init->DualAddressMode = I2C_DUALADDRESS_DISABLED; - init->GeneralCallMode = I2C_GENERALCALL_DISABLED; - init->NoStretchMode = I2C_NOSTRETCH_DISABLE; - init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS; - init->OwnAddress2 = 0; // unused - if (freq != -1) { - i2c_set_baudrate(init, MIN(freq, MICROPY_HW_I2C_BAUDRATE_MAX)); - } - - *self->use_dma = false; - - // init the I2C bus - i2c_deinit(self->i2c); - i2c_init(self->i2c); -} - -STATIC void i2c_reset_after_error(I2C_HandleTypeDef *i2c) { - // wait for bus-busy flag to be cleared, with a timeout - for (int timeout = 50; timeout > 0; --timeout) { - if (!__HAL_I2C_GET_FLAG(i2c, I2C_FLAG_BUSY)) { - // stop bit was generated and bus is back to normal - return; - } - mp_hal_delay_ms(1); - } - // bus was/is busy, need to reset the peripheral to get it to work again - i2c_deinit(i2c); - i2c_init(i2c); -} - -void i2c_ev_irq_handler(mp_uint_t i2c_id) { - I2C_HandleTypeDef *hi2c; - - switch (i2c_id) { - #if defined(MICROPY_HW_I2C1_SCL) - case 1: - hi2c = &I2CHandle1; - break; - #endif - #if defined(MICROPY_HW_I2C2_SCL) - case 2: - hi2c = &I2CHandle2; - break; - #endif - #if defined(MICROPY_HW_I2C3_SCL) - case 3: - hi2c = &I2CHandle3; - break; - #endif - #if defined(MICROPY_HW_I2C4_SCL) - case 4: - hi2c = &I2CHandle4; - break; - #endif - default: - return; - } - - #if defined(MCU_SERIES_F4) - - if (hi2c->Instance->SR1 & I2C_FLAG_BTF && hi2c->State == HAL_I2C_STATE_BUSY_TX) { - if (hi2c->XferCount != 0U) { - hi2c->Instance->DR = *hi2c->pBuffPtr++; - hi2c->XferCount--; - } else { - __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); - if (hi2c->XferOptions != I2C_FIRST_FRAME) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - hi2c->Mode = HAL_I2C_MODE_NONE; - hi2c->State = HAL_I2C_STATE_READY; - } - } - - #else - - // if not an F4 MCU, use the HAL's IRQ handler - HAL_I2C_EV_IRQHandler(hi2c); - - #endif -} - -void i2c_er_irq_handler(mp_uint_t i2c_id) { - I2C_HandleTypeDef *hi2c; - - switch (i2c_id) { - #if defined(MICROPY_HW_I2C1_SCL) - case 1: - hi2c = &I2CHandle1; - break; - #endif - #if defined(MICROPY_HW_I2C2_SCL) - case 2: - hi2c = &I2CHandle2; - break; - #endif - #if defined(MICROPY_HW_I2C3_SCL) - case 3: - hi2c = &I2CHandle3; - break; - #endif - #if defined(MICROPY_HW_I2C4_SCL) - case 4: - hi2c = &I2CHandle4; - break; - #endif - default: - return; - } - - #if defined(MCU_SERIES_F4) - - uint32_t sr1 = hi2c->Instance->SR1; - - // I2C Bus error - if (sr1 & I2C_FLAG_BERR) { - hi2c->ErrorCode |= HAL_I2C_ERROR_BERR; - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR); - } - - // I2C Arbitration Loss error - if (sr1 & I2C_FLAG_ARLO) { - hi2c->ErrorCode |= HAL_I2C_ERROR_ARLO; - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO); - } - - // I2C Acknowledge failure - if (sr1 & I2C_FLAG_AF) { - hi2c->ErrorCode |= HAL_I2C_ERROR_AF; - SET_BIT(hi2c->Instance->CR1,I2C_CR1_STOP); - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); - } - - // I2C Over-Run/Under-Run - if (sr1 & I2C_FLAG_OVR) { - hi2c->ErrorCode |= HAL_I2C_ERROR_OVR; - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR); - } - - #else - - // if not an F4 MCU, use the HAL's IRQ handler - HAL_I2C_ER_IRQHandler(hi2c); - - #endif -} - -STATIC HAL_StatusTypeDef i2c_wait_dma_finished(I2C_HandleTypeDef *i2c, uint32_t timeout) { - // Note: we can't use WFI to idle in this loop because the DMA completion - // interrupt may occur before the WFI. Hence we miss it and have to wait - // until the next sys-tick (up to 1ms). - uint32_t start = HAL_GetTick(); - while (HAL_I2C_GetState(i2c) != HAL_I2C_STATE_READY) { - if (HAL_GetTick() - start >= timeout) { - return HAL_TIMEOUT; - } - } - return HAL_OK; -} - -/******************************************************************************/ -/* MicroPython bindings */ - -static inline bool in_master_mode(pyb_i2c_obj_t *self) { return self->i2c->Init.OwnAddress1 == PYB_I2C_MASTER_ADDRESS; } - -STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - pyb_i2c_obj_t *self = self_in; - - uint i2c_num = 0; - if (0) { } - #if defined(MICROPY_HW_I2C1_SCL) - else if (self->i2c->Instance == I2C1) { i2c_num = 1; } - #endif - #if defined(MICROPY_HW_I2C2_SCL) - else if (self->i2c->Instance == I2C2) { i2c_num = 2; } - #endif - #if defined(MICROPY_HW_I2C3_SCL) - else if (self->i2c->Instance == I2C3) { i2c_num = 3; } - #endif - #if defined(MICROPY_HW_I2C4_SCL) - else if (self->i2c->Instance == I2C4) { i2c_num = 4; } - #endif - - if (self->i2c->State == HAL_I2C_STATE_RESET) { - mp_printf(print, "I2C(%u)", i2c_num); - } else { - if (in_master_mode(self)) { - mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, i2c_get_baudrate(&self->i2c->Init)); - } else { - mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f); - } - } -} - -/// \method init(mode, *, addr=0x12, baudrate=400000, gencall=False) -/// -/// Initialise the I2C bus with the given parameters: -/// -/// - `mode` must be either `I2C.MASTER` or `I2C.SLAVE` -/// - `addr` is the 7-bit address (only sensible for a slave) -/// - `baudrate` is the SCL clock rate (only sensible for a master) -/// - `gencall` is whether to support general call mode -STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_mode, MP_ARG_INT, {.u_int = PYB_I2C_MASTER} }, - { MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x12} }, - { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_HW_I2C_BAUDRATE_DEFAULT} }, - { MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_dma, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - }; - - // 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 the I2C configuration values - I2C_InitTypeDef *init = &self->i2c->Init; - - if (args[0].u_int == PYB_I2C_MASTER) { - // use a special address to indicate we are a master - init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS; - } else { - init->OwnAddress1 = (args[1].u_int << 1) & 0xfe; - } - - i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX)); - init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; - init->DualAddressMode = I2C_DUALADDRESS_DISABLED; - init->GeneralCallMode = args[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED; - init->OwnAddress2 = 0; // unused - init->NoStretchMode = I2C_NOSTRETCH_DISABLE; - - *self->use_dma = args[4].u_bool; - - // init the I2C bus - i2c_deinit(self->i2c); - i2c_init(self->i2c); - - return mp_const_none; -} - -/// \classmethod \constructor(bus, ...) -/// -/// Construct an I2C object on the given bus. `bus` can be 1 or 2. -/// With no additional parameters, the I2C object is created but not -/// initialised (it has the settings from the last initialisation of -/// the bus, if any). If extra arguments are given, the bus is initialised. -/// See `init` for parameters of initialisation. -/// -/// The physical pins of the I2C busses are: -/// -/// - `I2C(1)` is on the X position: `(SCL, SDA) = (X9, X10) = (PB6, PB7)` -/// - `I2C(2)` is on the Y position: `(SCL, SDA) = (Y9, Y10) = (PB10, PB11)` -STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - // check arguments - mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); - - // work out i2c bus - int i2c_id = 0; - if (MP_OBJ_IS_STR(args[0])) { - const char *port = mp_obj_str_get_str(args[0]); - if (0) { - #ifdef MICROPY_HW_I2C1_NAME - } else if (strcmp(port, MICROPY_HW_I2C1_NAME) == 0) { - i2c_id = 1; - #endif - #ifdef MICROPY_HW_I2C2_NAME - } else if (strcmp(port, MICROPY_HW_I2C2_NAME) == 0) { - i2c_id = 2; - #endif - #ifdef MICROPY_HW_I2C3_NAME - } else if (strcmp(port, MICROPY_HW_I2C3_NAME) == 0) { - i2c_id = 3; - #endif - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "I2C(%s) doesn't exist", port)); - } - } else { - i2c_id = mp_obj_get_int(args[0]); - if (i2c_id < 1 || i2c_id > MP_ARRAY_SIZE(pyb_i2c_obj) - || pyb_i2c_obj[i2c_id - 1].i2c == NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "I2C(%d) doesn't exist", i2c_id)); - } - } - - // get I2C object - const pyb_i2c_obj_t *i2c_obj = &pyb_i2c_obj[i2c_id - 1]; - - if (n_args > 1 || n_kw > 0) { - // start the peripheral - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - pyb_i2c_init_helper(i2c_obj, n_args - 1, args + 1, &kw_args); - } - - return (mp_obj_t)i2c_obj; -} - -STATIC mp_obj_t pyb_i2c_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - return pyb_i2c_init_helper(args[0], n_args - 1, args + 1, kw_args); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init); - -/// \method deinit() -/// Turn off the I2C bus. -STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) { - pyb_i2c_obj_t *self = self_in; - i2c_deinit(self->i2c); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit); - -/// \method is_ready(addr) -/// Check if an I2C device responds to the given address. Only valid when in master mode. -STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) { - pyb_i2c_obj_t *self = self_in; - - if (!in_master_mode(self)) { - mp_raise_TypeError("I2C must be a master"); - } - - mp_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1; - - for (int i = 0; i < 10; i++) { - HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, i2c_addr, 10, 200); - if (status == HAL_OK) { - return mp_const_true; - } - } - - return mp_const_false; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready); - -/// \method scan() -/// Scan all I2C addresses from 0x08 to 0x77 and return a list of those that respond. -/// Only valid when in master mode. -STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) { - pyb_i2c_obj_t *self = self_in; - - if (!in_master_mode(self)) { - mp_raise_TypeError("I2C must be a master"); - } - - mp_obj_t list = mp_obj_new_list(0, NULL); - - for (uint addr = 0x08; addr <= 0x77; addr++) { - HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, addr << 1, 1, 200); - if (status == HAL_OK) { - mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); - } - } - - return list; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan); - -/// \method send(send, addr=0x00, timeout=5000) -/// Send data on the bus: -/// -/// - `send` is the data to send (an integer to send, or a buffer object) -/// - `addr` is the address to send to (only required in master mode) -/// - `timeout` is the timeout in milliseconds to wait for the send -/// -/// Return value: `None`. -STATIC mp_obj_t pyb_i2c_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, - }; - - // parse args - pyb_i2c_obj_t *self = 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 the buffer to send from - mp_buffer_info_t bufinfo; - uint8_t data[1]; - pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); - - // if option is set and IRQs are enabled then we can use DMA - bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; - - DMA_HandleTypeDef tx_dma; - if (use_dma) { - dma_init(&tx_dma, self->tx_dma_descr, self->i2c); - self->i2c->hdmatx = &tx_dma; - self->i2c->hdmarx = NULL; - } - - // send the data - HAL_StatusTypeDef status; - if (in_master_mode(self)) { - if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) { - if (use_dma) { - dma_deinit(self->tx_dma_descr); - } - mp_raise_TypeError("addr argument required"); - } - mp_uint_t i2c_addr = args[1].u_int << 1; - if (!use_dma) { - status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, args[2].u_int); - } else { - MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len); - status = HAL_I2C_Master_Transmit_DMA(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len); - } - } else { - if (!use_dma) { - status = HAL_I2C_Slave_Transmit(self->i2c, bufinfo.buf, bufinfo.len, args[2].u_int); - } else { - MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len); - status = HAL_I2C_Slave_Transmit_DMA(self->i2c, bufinfo.buf, bufinfo.len); - } - } - - // if we used DMA, wait for it to finish - if (use_dma) { - if (status == HAL_OK) { - status = i2c_wait_dma_finished(self->i2c, args[2].u_int); - } - dma_deinit(self->tx_dma_descr); - } - - if (status != HAL_OK) { - i2c_reset_after_error(self->i2c); - mp_hal_raise(status); - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send); - -/// \method recv(recv, addr=0x00, timeout=5000) -/// -/// Receive data on the bus: -/// -/// - `recv` can be an integer, which is the number of bytes to receive, -/// or a mutable buffer, which will be filled with received bytes -/// - `addr` is the address to receive from (only required in master mode) -/// - `timeout` is the timeout in milliseconds to wait for the receive -/// -/// Return value: if `recv` is an integer then a new buffer of the bytes received, -/// otherwise the same buffer that was passed in to `recv`. -STATIC mp_obj_t pyb_i2c_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, - }; - - // parse args - pyb_i2c_obj_t *self = 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 the buffer to receive into - vstr_t vstr; - mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); - - // if option is set and IRQs are enabled then we can use DMA - bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; - - DMA_HandleTypeDef rx_dma; - if (use_dma) { - dma_init(&rx_dma, self->rx_dma_descr, self->i2c); - self->i2c->hdmatx = NULL; - self->i2c->hdmarx = &rx_dma; - } - - // receive the data - HAL_StatusTypeDef status; - if (in_master_mode(self)) { - if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) { - mp_raise_TypeError("addr argument required"); - } - mp_uint_t i2c_addr = args[1].u_int << 1; - if (!use_dma) { - status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len, args[2].u_int); - } else { - MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len); - status = HAL_I2C_Master_Receive_DMA(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len); - } - } else { - if (!use_dma) { - status = HAL_I2C_Slave_Receive(self->i2c, (uint8_t*)vstr.buf, vstr.len, args[2].u_int); - } else { - MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len); - status = HAL_I2C_Slave_Receive_DMA(self->i2c, (uint8_t*)vstr.buf, vstr.len); - } - } - - // if we used DMA, wait for it to finish - if (use_dma) { - if (status == HAL_OK) { - status = i2c_wait_dma_finished(self->i2c, args[2].u_int); - } - dma_deinit(self->rx_dma_descr); - } - - if (status != HAL_OK) { - i2c_reset_after_error(self->i2c); - mp_hal_raise(status); - } - - // return the received data - if (o_ret != MP_OBJ_NULL) { - return o_ret; - } else { - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); - } -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv); - -/// \method mem_read(data, addr, memaddr, timeout=5000, addr_size=8) -/// -/// Read from the memory of an I2C device: -/// -/// - `data` can be an integer or a buffer to read into -/// - `addr` is the I2C device address -/// - `memaddr` is the memory location within the I2C device -/// - `timeout` is the timeout in milliseconds to wait for the read -/// - `addr_size` selects width of memaddr: 8 or 16 bits -/// -/// Returns the read data. -/// This is only valid in master mode. -STATIC const mp_arg_t pyb_i2c_mem_read_allowed_args[] = { - { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, - { MP_QSTR_addr_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, -}; - -STATIC mp_obj_t pyb_i2c_mem_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // parse args - pyb_i2c_obj_t *self = pos_args[0]; - mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args); - - if (!in_master_mode(self)) { - mp_raise_TypeError("I2C must be a master"); - } - - // get the buffer to read into - vstr_t vstr; - mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); - - // get the addresses - mp_uint_t i2c_addr = args[1].u_int << 1; - mp_uint_t mem_addr = args[2].u_int; - // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width - mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT; - if (args[4].u_int != 8) { - mem_addr_size = I2C_MEMADD_SIZE_16BIT; - } - - // if option is set and IRQs are enabled then we can use DMA - bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; - - HAL_StatusTypeDef status; - if (!use_dma) { - status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len, args[3].u_int); - } else { - DMA_HandleTypeDef rx_dma; - dma_init(&rx_dma, self->rx_dma_descr, self->i2c); - self->i2c->hdmatx = NULL; - self->i2c->hdmarx = &rx_dma; - MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len); - status = HAL_I2C_Mem_Read_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len); - if (status == HAL_OK) { - status = i2c_wait_dma_finished(self->i2c, args[3].u_int); - } - dma_deinit(self->rx_dma_descr); - } - - if (status != HAL_OK) { - i2c_reset_after_error(self->i2c); - mp_hal_raise(status); - } - - // return the read data - if (o_ret != MP_OBJ_NULL) { - return o_ret; - } else { - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); - } -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read); - -/// \method mem_write(data, addr, memaddr, timeout=5000, addr_size=8) -/// -/// Write to the memory of an I2C device: -/// -/// - `data` can be an integer or a buffer to write from -/// - `addr` is the I2C device address -/// - `memaddr` is the memory location within the I2C device -/// - `timeout` is the timeout in milliseconds to wait for the write -/// - `addr_size` selects width of memaddr: 8 or 16 bits -/// -/// Returns `None`. -/// This is only valid in master mode. -STATIC mp_obj_t pyb_i2c_mem_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // parse args (same as mem_read) - pyb_i2c_obj_t *self = pos_args[0]; - mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args); - - if (!in_master_mode(self)) { - mp_raise_TypeError("I2C must be a master"); - } - - // get the buffer to write from - mp_buffer_info_t bufinfo; - uint8_t data[1]; - pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); - - // get the addresses - mp_uint_t i2c_addr = args[1].u_int << 1; - mp_uint_t mem_addr = args[2].u_int; - // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width - mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT; - if (args[4].u_int != 8) { - mem_addr_size = I2C_MEMADD_SIZE_16BIT; - } - - // if option is set and IRQs are enabled then we can use DMA - bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; - - HAL_StatusTypeDef status; - if (!use_dma) { - status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len, args[3].u_int); - } else { - DMA_HandleTypeDef tx_dma; - dma_init(&tx_dma, self->tx_dma_descr, self->i2c); - self->i2c->hdmatx = &tx_dma; - self->i2c->hdmarx = NULL; - MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len); - status = HAL_I2C_Mem_Write_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len); - if (status == HAL_OK) { - status = i2c_wait_dma_finished(self->i2c, args[3].u_int); - } - dma_deinit(self->tx_dma_descr); - } - - if (status != HAL_OK) { - i2c_reset_after_error(self->i2c); - mp_hal_raise(status); - } - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_write_obj, 1, pyb_i2c_mem_write); - -STATIC const mp_rom_map_elem_t pyb_i2c_locals_dict_table[] = { - // instance methods - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_i2c_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_i2c_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_is_ready), MP_ROM_PTR(&pyb_i2c_is_ready_obj) }, - { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&pyb_i2c_scan_obj) }, - { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_i2c_send_obj) }, - { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_i2c_recv_obj) }, - { MP_ROM_QSTR(MP_QSTR_mem_read), MP_ROM_PTR(&pyb_i2c_mem_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_mem_write), MP_ROM_PTR(&pyb_i2c_mem_write_obj) }, - - // class constants - /// \constant MASTER - for initialising the bus to master mode - /// \constant SLAVE - for initialising the bus to slave mode - { MP_ROM_QSTR(MP_QSTR_MASTER), MP_ROM_INT(PYB_I2C_MASTER) }, - { MP_ROM_QSTR(MP_QSTR_SLAVE), MP_ROM_INT(PYB_I2C_SLAVE) }, -}; - -STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table); - -const mp_obj_type_t pyb_i2c_type = { - { &mp_type_type }, - .name = MP_QSTR_I2C, - .print = pyb_i2c_print, - .make_new = pyb_i2c_make_new, - .locals_dict = (mp_obj_dict_t*)&pyb_i2c_locals_dict, -}; +#endif // MICROPY_HW_ENABLE_HW_I2C diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h index 6affe3973b..5599f41235 100644 --- a/ports/stm32/i2c.h +++ b/ports/stm32/i2c.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_I2C_H -#define MICROPY_INCLUDED_STMHAL_I2C_H +#ifndef MICROPY_INCLUDED_STM32_I2C_H +#define MICROPY_INCLUDED_STM32_I2C_H #include "dma.h" @@ -42,14 +42,24 @@ typedef struct _pyb_i2c_obj_t { extern I2C_HandleTypeDef I2CHandle1; extern I2C_HandleTypeDef I2CHandle2; extern I2C_HandleTypeDef I2CHandle3; +extern I2C_HandleTypeDef I2CHandle4; extern const mp_obj_type_t pyb_i2c_type; extern const pyb_i2c_obj_t pyb_i2c_obj[4]; void i2c_init0(void); -void i2c_init(I2C_HandleTypeDef *i2c); -void i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq); -uint32_t i2c_get_baudrate(I2C_InitTypeDef *init); +void pyb_i2c_init(I2C_HandleTypeDef *i2c); +void pyb_i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq); +uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c); void i2c_ev_irq_handler(mp_uint_t i2c_id); void i2c_er_irq_handler(mp_uint_t i2c_id); -#endif // MICROPY_INCLUDED_STMHAL_I2C_H +typedef I2C_TypeDef i2c_t; + +int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq); +int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop); +int i2c_read(i2c_t *i2c, uint8_t *dest, size_t len, size_t next_len); +int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len); +int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop); +int i2c_writeto(i2c_t *i2c, uint16_t addr, const uint8_t *src, size_t len, bool stop); + +#endif // MICROPY_INCLUDED_STM32_I2C_H diff --git a/ports/stm32/i2cslave.c b/ports/stm32/i2cslave.c new file mode 100644 index 0000000000..473f0c8c55 --- /dev/null +++ b/ports/stm32/i2cslave.c @@ -0,0 +1,101 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "i2cslave.h" + +#if defined(STM32F4) + +void i2c_slave_init_helper(i2c_slave_t *i2c, int addr) { + i2c->CR2 = I2C_CR2_ITBUFEN | I2C_CR2_ITEVTEN | 4 << I2C_CR2_FREQ_Pos; + i2c->OAR1 = 1 << 14 | addr << 1; + i2c->OAR2 = 0; + i2c->CR1 = I2C_CR1_ACK | I2C_CR1_PE; +} + +void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { + uint32_t sr1 = i2c->SR1; + if (sr1 & I2C_SR1_ADDR) { + // Address matched + // Read of SR1, SR2 needed to clear ADDR bit + sr1 = i2c->SR1; + uint32_t sr2 = i2c->SR2; + i2c_slave_process_addr_match((sr2 >> I2C_SR2_TRA_Pos) & 1); + } + if (sr1 & I2C_SR1_TXE) { + i2c->DR = i2c_slave_process_tx_byte(); + } + if (sr1 & I2C_SR1_RXNE) { + i2c_slave_process_rx_byte(i2c->DR); + } + if (sr1 & I2C_SR1_STOPF) { + // STOPF only set at end of RX mode (in TX mode AF is set on NACK) + // Read of SR1, write CR1 needed to clear STOPF bit + sr1 = i2c->SR1; + i2c->CR1 &= ~I2C_CR1_ACK; + i2c_slave_process_rx_end(); + i2c->CR1 |= I2C_CR1_ACK; + } +} + +#elif defined(STM32F7) + +void i2c_slave_init_helper(i2c_slave_t *i2c, int addr) { + i2c->CR1 = I2C_CR1_STOPIE | I2C_CR1_ADDRIE | I2C_CR1_RXIE | I2C_CR1_TXIE; + i2c->CR2 = 0; + i2c->OAR1 = I2C_OAR1_OA1EN | addr << 1; + i2c->OAR2 = 0; + i2c->CR1 |= I2C_CR1_PE; +} + +void i2c_slave_ev_irq_handler(i2c_slave_t *i2c) { + uint32_t isr = i2c->ISR; + if (isr & I2C_ISR_ADDR) { + // Address matched + // Set TXE so that TXDR is flushed and ready for the first byte + i2c->ISR = I2C_ISR_TXE; + i2c->ICR = I2C_ICR_ADDRCF; + i2c_slave_process_addr_match(0); + } + if (isr & I2C_ISR_TXIS) { + i2c->TXDR = i2c_slave_process_tx_byte(); + } + if (isr & I2C_ISR_RXNE) { + i2c_slave_process_rx_byte(i2c->RXDR); + } + if (isr & I2C_ISR_STOPF) { + // STOPF only set for STOP condition, not a repeated START + i2c->ICR = I2C_ICR_STOPCF; + i2c->OAR1 &= ~I2C_OAR1_OA1EN; + if (i2c->ISR & I2C_ISR_DIR) { + //i2c_slave_process_tx_end(); + } else { + i2c_slave_process_rx_end(); + } + i2c->OAR1 |= I2C_OAR1_OA1EN; + } +} + +#endif diff --git a/ports/stm32/i2cslave.h b/ports/stm32/i2cslave.h new file mode 100644 index 0000000000..ac35c0cc82 --- /dev/null +++ b/ports/stm32/i2cslave.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_I2CSLAVE_H +#define MICROPY_INCLUDED_STM32_I2CSLAVE_H + +#include STM32_HAL_H + +typedef I2C_TypeDef i2c_slave_t; + +void i2c_slave_init_helper(i2c_slave_t *i2c, int addr); + +static inline void i2c_slave_init(i2c_slave_t *i2c, int irqn, int irq_pri, int addr) { + int en_bit = RCC_APB1ENR_I2C1EN_Pos + ((uintptr_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE); + RCC->APB1ENR |= 1 << en_bit; + volatile uint32_t tmp = RCC->APB1ENR; // Delay after enabling clock + (void)tmp; + + i2c_slave_init_helper(i2c, addr); + + NVIC_SetPriority(irqn, irq_pri); + NVIC_EnableIRQ(irqn); +} + +static inline void i2c_slave_shutdown(i2c_slave_t *i2c, int irqn) { + i2c->CR1 = 0; + NVIC_DisableIRQ(irqn); +} + +void i2c_slave_ev_irq_handler(i2c_slave_t *i2c); + +// These should be provided externally +int i2c_slave_process_addr_match(int rw); +int i2c_slave_process_rx_byte(uint8_t val); +void i2c_slave_process_rx_end(void); +uint8_t i2c_slave_process_tx_byte(void); + +#endif // MICROPY_INCLUDED_STM32_I2CSLAVE_H diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index 2cf58639ea..3fe20867fe 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -23,8 +23,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_IRQ_H -#define MICROPY_INCLUDED_STMHAL_IRQ_H +#ifndef MICROPY_INCLUDED_STM32_IRQ_H +#define MICROPY_INCLUDED_STM32_IRQ_H + +// Use this macro together with NVIC_SetPriority to indicate that an IRQn is non-negative, +// which helps the compiler optimise the resulting inline function. +#define IRQn_NONNEG(pri) ((pri) & 0x7f) // these states correspond to values from query_irq, enable_irq and disable_irq #define IRQ_STATE_DISABLED (0x00000001) @@ -98,55 +102,57 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); // The following interrupts are arranged from highest priority to lowest // priority to make it a bit easier to figure out. -// Priority Sub-Priority -// -------- ------------ +#if __CORTEX_M == 0 + //#def IRQ_PRI_SYSTICK 0 -//#def IRQ_SUBPRI_SYSTICK 0 +#define IRQ_PRI_UART 1 +#define IRQ_PRI_FLASH 1 +#define IRQ_PRI_SDIO 1 +#define IRQ_PRI_DMA 1 +#define IRQ_PRI_OTG_FS 2 +#define IRQ_PRI_OTG_HS 2 +#define IRQ_PRI_TIM5 2 +#define IRQ_PRI_CAN 2 +#define IRQ_PRI_TIMX 2 +#define IRQ_PRI_EXTINT 2 +#define IRQ_PRI_PENDSV 3 +#define IRQ_PRI_RTC_WKUP 3 + +#else + +//#def IRQ_PRI_SYSTICK NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0) // The UARTs have no FIFOs, so if they don't get serviced quickly then characters // get dropped. The handling for each character only consumes about 0.5 usec -#define IRQ_PRI_UART 1 -#define IRQ_SUBPRI_UART 0 +#define IRQ_PRI_UART NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0) // Flash IRQ must be higher priority than interrupts of all those components // that rely on the flash storage. -#define IRQ_PRI_FLASH 2 -#define IRQ_SUBPRI_FLASH 0 +#define IRQ_PRI_FLASH NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 2, 0) // SDIO must be higher priority than DMA for SDIO DMA transfers to work. -#define IRQ_PRI_SDIO 4 -#define IRQ_SUBPRI_SDIO 0 +#define IRQ_PRI_SDIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 4, 0) // DMA should be higher priority than USB, since USB Mass Storage calls // into the sdcard driver which waits for the DMA to complete. -#define IRQ_PRI_DMA 5 -#define IRQ_SUBPRI_DMA 0 +#define IRQ_PRI_DMA NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 5, 0) -#define IRQ_PRI_OTG_FS 6 -#define IRQ_SUBPRI_OTG_FS 0 +#define IRQ_PRI_OTG_FS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) +#define IRQ_PRI_OTG_HS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) +#define IRQ_PRI_TIM5 NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0) -#define IRQ_PRI_OTG_HS 6 -#define IRQ_SUBPRI_OTG_HS 0 - -#define IRQ_PRI_TIM5 6 -#define IRQ_SUBPRI_TIM5 0 - -#define IRQ_PRI_CAN 7 -#define IRQ_SUBPRI_CAN 0 +#define IRQ_PRI_CAN NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 7, 0) // Interrupt priority for non-special timers. -#define IRQ_PRI_TIMX 13 -#define IRQ_SUBPRI_TIMX 0 +#define IRQ_PRI_TIMX NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 13, 0) -#define IRQ_PRI_EXTINT 14 -#define IRQ_SUBPRI_EXTINT 0 +#define IRQ_PRI_EXTINT NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0) // PENDSV should be at the lowst priority so that other interrupts complete // before exception is raised. -#define IRQ_PRI_PENDSV 15 -#define IRQ_SUBPRI_PENDSV 0 +#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +#define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) -#define IRQ_PRI_RTC_WKUP 15 -#define IRQ_SUBPRI_RTC_WKUP 0 +#endif -#endif // MICROPY_INCLUDED_STMHAL_IRQ_H +#endif // MICROPY_INCLUDED_STM32_IRQ_H diff --git a/ports/stm32/lcd.c b/ports/stm32/lcd.c index 488df1699c..10fb54eb5f 100644 --- a/ports/stm32/lcd.c +++ b/ports/stm32/lcd.c @@ -33,7 +33,6 @@ #if MICROPY_HW_HAS_LCD #include "pin.h" -#include "genhdr/pins.h" #include "bufhelper.h" #include "spi.h" #include "font_petme128_8x8.h" @@ -89,7 +88,7 @@ typedef struct _pyb_lcd_obj_t { mp_obj_base_t base; // hardware control for the LCD - SPI_HandleTypeDef *spi; + const spi_t *spi; const pin_obj_t *pin_cs1; const pin_obj_t *pin_rst; const pin_obj_t *pin_a0; @@ -119,7 +118,7 @@ STATIC void lcd_out(pyb_lcd_obj_t *lcd, int instr_data, uint8_t i) { mp_hal_pin_high(lcd->pin_a0); // A0=1; select data reg } lcd_delay(); - HAL_SPI_Transmit(lcd->spi, &i, 1, 1000); + HAL_SPI_Transmit(lcd->spi->spi, &i, 1, 1000); lcd_delay(); mp_hal_pin_high(lcd->pin_cs1); // CS=1; disable } @@ -207,29 +206,29 @@ STATIC mp_obj_t pyb_lcd_make_new(const mp_obj_type_t *type, size_t n_args, size_ // configure pins // TODO accept an SPI object and pin objects for full customisation if ((lcd_id[0] | 0x20) == 'x' && lcd_id[1] == '\0') { - lcd->spi = &SPIHandle1; - lcd->pin_cs1 = &pyb_pin_X3; - lcd->pin_rst = &pyb_pin_X4; - lcd->pin_a0 = &pyb_pin_X5; - lcd->pin_bl = &pyb_pin_X12; + lcd->spi = &spi_obj[0]; + lcd->pin_cs1 = pyb_pin_X3; + lcd->pin_rst = pyb_pin_X4; + lcd->pin_a0 = pyb_pin_X5; + lcd->pin_bl = pyb_pin_X12; } else if ((lcd_id[0] | 0x20) == 'y' && lcd_id[1] == '\0') { - lcd->spi = &SPIHandle2; - lcd->pin_cs1 = &pyb_pin_Y3; - lcd->pin_rst = &pyb_pin_Y4; - lcd->pin_a0 = &pyb_pin_Y5; - lcd->pin_bl = &pyb_pin_Y12; + lcd->spi = &spi_obj[1]; + lcd->pin_cs1 = pyb_pin_Y3; + lcd->pin_rst = pyb_pin_Y4; + lcd->pin_a0 = pyb_pin_Y5; + lcd->pin_bl = pyb_pin_Y12; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LCD(%s) doesn't exist", lcd_id)); } // init the SPI bus - SPI_InitTypeDef *init = &lcd->spi->Init; + SPI_InitTypeDef *init = &lcd->spi->spi->Init; init->Mode = SPI_MODE_MASTER; // compute the baudrate prescaler from the desired baudrate // select a prescaler that yields at most the desired baudrate uint spi_clock; - if (lcd->spi->Instance == SPI1) { + if (lcd->spi->spi->Instance == SPI1) { // SPI1 is on APB2 spi_clock = HAL_RCC_GetPCLK2Freq(); } else { diff --git a/ports/stm32/lcd.h b/ports/stm32/lcd.h index c0d9bd97da..98f904848f 100644 --- a/ports/stm32/lcd.h +++ b/ports/stm32/lcd.h @@ -23,9 +23,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_LCD_H -#define MICROPY_INCLUDED_STMHAL_LCD_H +#ifndef MICROPY_INCLUDED_STM32_LCD_H +#define MICROPY_INCLUDED_STM32_LCD_H extern const mp_obj_type_t pyb_lcd_type; -#endif // MICROPY_INCLUDED_STMHAL_LCD_H +#endif // MICROPY_INCLUDED_STM32_LCD_H diff --git a/ports/stm32/led.c b/ports/stm32/led.c index 9bbcaa6b30..71c674ab96 100644 --- a/ports/stm32/led.c +++ b/ports/stm32/led.c @@ -31,7 +31,6 @@ #include "timer.h" #include "led.h" #include "pin.h" -#include "genhdr/pins.h" #if defined(MICROPY_HW_LED1) @@ -52,13 +51,13 @@ typedef struct _pyb_led_obj_t { } pyb_led_obj_t; STATIC const pyb_led_obj_t pyb_led_obj[] = { - {{&pyb_led_type}, 1, &MICROPY_HW_LED1}, + {{&pyb_led_type}, 1, MICROPY_HW_LED1}, #if defined(MICROPY_HW_LED2) - {{&pyb_led_type}, 2, &MICROPY_HW_LED2}, + {{&pyb_led_type}, 2, MICROPY_HW_LED2}, #if defined(MICROPY_HW_LED3) - {{&pyb_led_type}, 3, &MICROPY_HW_LED3}, + {{&pyb_led_type}, 3, MICROPY_HW_LED3}, #if defined(MICROPY_HW_LED4) - {{&pyb_led_type}, 4, &MICROPY_HW_LED4}, + {{&pyb_led_type}, 4, MICROPY_HW_LED4}, #endif #endif #endif @@ -282,7 +281,7 @@ void led_debug(int n, int delay) { void led_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_led_obj_t *self = self_in; - mp_printf(print, "LED(%lu)", self->led_id); + mp_printf(print, "LED(%u)", self->led_id); } /// \classmethod \constructor(id) diff --git a/ports/stm32/led.h b/ports/stm32/led.h index f1b05d1e28..1cc96b75ab 100644 --- a/ports/stm32/led.h +++ b/ports/stm32/led.h @@ -23,25 +23,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_LED_H -#define MICROPY_INCLUDED_STMHAL_LED_H +#ifndef MICROPY_INCLUDED_STM32_LED_H +#define MICROPY_INCLUDED_STM32_LED_H typedef enum { - // PYBv3 - PYB_LED_R1 = 1, - PYB_LED_R2 = 2, - PYB_LED_G1 = 3, - PYB_LED_G2 = 4, - // PYBv4 PYB_LED_RED = 1, PYB_LED_GREEN = 2, PYB_LED_YELLOW = 3, PYB_LED_BLUE = 4, - //STM32F4DISC - PYB_LED_R = 1, - PYB_LED_G = 2, - PYB_LED_B = 3, - PYB_LED_O = 4, } pyb_led_t; void led_init(void); @@ -51,4 +40,4 @@ void led_debug(int value, int delay); extern const mp_obj_type_t pyb_led_type; -#endif // MICROPY_INCLUDED_STMHAL_LED_H +#endif // MICROPY_INCLUDED_STM32_LED_H diff --git a/ports/stm32/lwip_inc/arch/cc.h b/ports/stm32/lwip_inc/arch/cc.h new file mode 100644 index 0000000000..635b1c8056 --- /dev/null +++ b/ports/stm32/lwip_inc/arch/cc.h @@ -0,0 +1,8 @@ +#ifndef MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H +#define MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H + +#include +#define LWIP_PLATFORM_DIAG(x) +#define LWIP_PLATFORM_ASSERT(x) { assert(1); } + +#endif // MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H diff --git a/ports/stm32/lwip_inc/arch/sys_arch.h b/ports/stm32/lwip_inc/arch/sys_arch.h new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/ports/stm32/lwip_inc/arch/sys_arch.h @@ -0,0 +1 @@ +// empty diff --git a/ports/stm32/lwip_inc/lwipopts.h b/ports/stm32/lwip_inc/lwipopts.h new file mode 100644 index 0000000000..b8ab8a2ab0 --- /dev/null +++ b/ports/stm32/lwip_inc/lwipopts.h @@ -0,0 +1,61 @@ +#ifndef MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H +#define MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H + +#include + +#define NO_SYS 1 +#define SYS_LIGHTWEIGHT_PROT 1 +#define MEM_ALIGNMENT 4 + +#define LWIP_CHKSUM_ALGORITHM 3 + +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_NETCONN 0 +#define LWIP_SOCKET 0 +#define LWIP_STATS 0 +#define LWIP_NETIF_HOSTNAME 1 + +#define LWIP_IPV6 0 +#define LWIP_DHCP 1 +#define LWIP_DHCP_CHECK_LINK_UP 1 +#define LWIP_DNS 1 +#define LWIP_IGMP 1 + +#define SO_REUSE 1 + +extern uint32_t rng_get(void); +#define LWIP_RAND() rng_get() + +// default +// lwip takes 15800 bytes; TCP d/l: 380k/s local, 7.2k/s remote +// TCP u/l is very slow + +#if 0 +// lwip takes 19159 bytes; TCP d/l and u/l are around 320k/s on local network +#define MEM_SIZE (5000) +#define TCP_WND (4 * TCP_MSS) +#define TCP_SND_BUF (4 * TCP_MSS) +#endif + +#if 1 +// lwip takes 26700 bytes; TCP dl/ul are around 750/600 k/s on local network +#define MEM_SIZE (8000) +#define TCP_MSS (800) +#define TCP_WND (8 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define MEMP_NUM_TCP_SEG (32) +#endif + +#if 0 +// lwip takes 45600 bytes; TCP dl/ul are around 1200/1000 k/s on local network +#define MEM_SIZE (16000) +#define TCP_MSS (1460) +#define TCP_WND (8 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define MEMP_NUM_TCP_SEG (32) +#endif + +typedef uint32_t sys_prot_t; + +#endif // MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 1be2151e3b..b7a9ea69bf 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Damien P. George + * Copyright (c) 2016-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,388 +31,92 @@ #include "py/mphal.h" #include "py/mperrno.h" #include "extmod/machine_i2c.h" -#include "genhdr/pins.h" #include "i2c.h" +#if MICROPY_HW_ENABLE_HW_I2C + STATIC const mp_obj_type_t machine_hard_i2c_type; -#if defined(MCU_SERIES_F4) - -// F4xx specific driver for I2C hardware peripheral -// The hardware-specific I2C code below is based heavily on the code from -// V1.5.2 of the STM32 CUBE F4 HAL. Its copyright notice is given here. -/* -* COPYRIGHT(c) 2016 STMicroelectronics -* -* Redistribution and use in source and binary forms, with or without modification, -* are permitted provided that the following conditions are met: -* 1. Redistributions of source code must retain the above copyright notice, -* this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following disclaimer in the documentation -* and/or other materials provided with the distribution. -* 3. Neither the name of STMicroelectronics nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) typedef struct _machine_hard_i2c_obj_t { mp_obj_base_t base; - const pyb_i2c_obj_t *pyb; - uint32_t *timeout; + i2c_t *i2c; + mp_hal_pin_obj_t scl; + mp_hal_pin_obj_t sda; } machine_hard_i2c_obj_t; -STATIC uint32_t machine_hard_i2c_timeout[4]; - STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { - {{&machine_hard_i2c_type}, &pyb_i2c_obj[0], &machine_hard_i2c_timeout[0]}, - {{&machine_hard_i2c_type}, &pyb_i2c_obj[1], &machine_hard_i2c_timeout[1]}, - {{&machine_hard_i2c_type}, &pyb_i2c_obj[2], &machine_hard_i2c_timeout[2]}, - {{&machine_hard_i2c_type}, &pyb_i2c_obj[3], &machine_hard_i2c_timeout[3]}, + #if defined(MICROPY_HW_I2C1_SCL) + {{&machine_hard_i2c_type}, I2C1, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C2_SCL) + {{&machine_hard_i2c_type}, I2C2, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C3_SCL) + {{&machine_hard_i2c_type}, I2C3, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C4_SCL) + {{&machine_hard_i2c_type}, I2C4, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, + #else + {{NULL}, NULL, NULL, NULL}, + #endif }; STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "I2C(%u, freq=%u, timeout=%u)", - self - &machine_hard_i2c_obj[0] + 1, - i2c_get_baudrate(&self->pyb->i2c->Init), - *self->timeout); -} -STATIC void machine_hard_i2c_init(const machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) { - *self->timeout = timeout; - i2c_init_freq(self->pyb, freq); -} + #if defined(STM32F4) -// this function is based on STM code -STATIC bool I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c) { - if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) { - /* Clear NACKF Flag */ - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); - return true; - } - return false; -} - -// this function is based on STM code -STATIC bool I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart) { - /* Wait until flag is set */ - while ((__HAL_I2C_GET_FLAG(hi2c, Flag) ? SET : RESET) == Status) { - if (Timeout != HAL_MAX_DELAY) { - if ((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) { - return false; - } - } - } - return true; -} - -// this function is based on STM code -STATIC int I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) { - while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) { - /* Check if a STOPF is detected */ - if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) { - /* Clear STOP Flag */ - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); - return -MP_EBUSY; - } - - /* Check for the Timeout */ - if ((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) { - return -MP_ETIMEDOUT; - } - } - return 0; -} - -// this function is based on STM code -STATIC int send_addr_byte(I2C_HandleTypeDef *hi2c, uint8_t addr_byte, uint32_t Timeout, uint32_t Tickstart) { - /* Generate Start */ - hi2c->Instance->CR1 |= I2C_CR1_START; - - /* Wait until SB flag is set */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart)) { - return -MP_ETIMEDOUT; - } - - /* Send slave address */ - hi2c->Instance->DR = addr_byte; - - /* Wait until ADDR flag is set */ - while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == RESET) { - if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) { - // nack received for addr, release the bus cleanly - hi2c->Instance->CR1 |= I2C_CR1_STOP; - __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); - return -MP_ENODEV; - } - - /* Check for the Timeout */ - if (Timeout != HAL_MAX_DELAY) { - if ((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) { - return -MP_ETIMEDOUT; - } - } - } - - return 0; -} - -// this function is based on STM code -int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { - machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)self_in; - I2C_HandleTypeDef *hi2c = self->pyb->i2c; - uint32_t Timeout = *self->timeout; - - /* Init tickstart for timeout management*/ - uint32_t tickstart = HAL_GetTick(); - -#if 0 - // TODO: for multi-master, here we could wait for the bus to be free - // we'd need a flag to tell if we were in the middle of a set of transactions - // (ie didn't send a stop bit in the last call) - /* Wait until BUSY flag is reset */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart)) { - return -MP_EBUSY; - } -#endif - - /* Check if the I2C is already enabled */ - if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) { - /* Enable I2C peripheral */ - __HAL_I2C_ENABLE(hi2c); - } - - /* Disable Pos */ - hi2c->Instance->CR1 &= ~I2C_CR1_POS; - - /* Enable Acknowledge */ - hi2c->Instance->CR1 |= I2C_CR1_ACK; - - /* Send Slave Address */ - int ret = send_addr_byte(hi2c, I2C_7BIT_ADD_READ(addr << 1), Timeout, tickstart); - if (ret != 0) { - return ret; - } - - if (len == 0U) { - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); - - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - } else if (len == 1U) { - /* Disable Acknowledge */ - hi2c->Instance->CR1 &= ~I2C_CR1_ACK; - - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); - - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - } else if (len == 2U) { - /* Disable Acknowledge */ - hi2c->Instance->CR1 &= ~I2C_CR1_ACK; - - /* Enable Pos */ - hi2c->Instance->CR1 |= I2C_CR1_POS; - - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + uint32_t freq = self->i2c->CR2 & 0x3f; + uint32_t ccr = self->i2c->CCR; + if (ccr & 0x8000) { + // Fast mode, assume duty cycle of 16/9 + freq = freq * 40000 / (ccr & 0xfff); } else { - /* Enable Acknowledge */ - hi2c->Instance->CR1 |= I2C_CR1_ACK; - - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); + // Standard mode + freq = freq * 500000 / (ccr & 0xfff); } - while (len > 0U) { - if (len <= 3U) { - if (len == 1U) { - /* Wait until RXNE flag is set */ - int ret = I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart); - if (ret != 0) { - return ret; - } + mp_printf(print, "I2C(%u, scl=%q, sda=%q, freq=%u)", + self - &machine_hard_i2c_obj[0] + 1, + mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda), + freq); - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - } else if (len == 2U) { - /* Wait until BTF flag is set */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) { - return -MP_ETIMEDOUT; - } + #else - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } + uint32_t timingr = self->i2c->TIMINGR; + uint32_t presc = timingr >> 28; + uint32_t sclh = timingr >> 8 & 0xff; + uint32_t scll = timingr & 0xff; + uint32_t freq = HAL_RCC_GetPCLK1Freq() / (presc + 1) / (sclh + scll + 2); + mp_printf(print, "I2C(%u, scl=%q, sda=%q, freq=%u, timingr=0x%08x)", + self - &machine_hard_i2c_obj[0] + 1, + mp_hal_pin_name(self->scl), mp_hal_pin_name(self->sda), + freq, timingr); - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - } else { - /* Wait until BTF flag is set */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) { - return -MP_ETIMEDOUT; - } - - /* Disable Acknowledge */ - hi2c->Instance->CR1 &= ~I2C_CR1_ACK; - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - - /* Wait until BTF flag is set */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) { - return -MP_ETIMEDOUT; - } - - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - } - } else { - /* Wait until RXNE flag is set */ - int ret = I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart); - if (ret != 0) { - return ret; - } - - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - - if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) { - /* Read data from DR */ - *dest++ = hi2c->Instance->DR; - len--; - } - } - } - - return 0; + #endif +} + +void machine_hard_i2c_init(machine_hard_i2c_obj_t *self, uint32_t freq, uint32_t timeout) { + (void)timeout; + i2c_init(self->i2c, self->scl, self->sda, freq); +} + +int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) { + machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + return i2c_readfrom(self->i2c, addr, dest, len, stop); } -// this function is based on STM code int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { - machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)self_in; - I2C_HandleTypeDef *hi2c = self->pyb->i2c; - uint32_t Timeout = *self->timeout; - - /* Init tickstart for timeout management*/ - uint32_t tickstart = HAL_GetTick(); - -#if 0 - // TODO: for multi-master, here we could wait for the bus to be free - // we'd need a flag to tell if we were in the middle of a set of transactions - // (ie didn't send a stop bit in the last call) - /* Wait until BUSY flag is reset */ - if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart)) { - return -MP_EBUSY; - } -#endif - - /* Check if the I2C is already enabled */ - if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) { - /* Enable I2C peripheral */ - __HAL_I2C_ENABLE(hi2c); - } - - /* Disable Pos */ - hi2c->Instance->CR1 &= ~I2C_CR1_POS; - - /* Send Slave Address */ - int ret = send_addr_byte(hi2c, I2C_7BIT_ADD_WRITE(addr << 1), Timeout, tickstart); - if (ret != 0) { - return ret; - } - - /* Clear ADDR flag */ - __HAL_I2C_CLEAR_ADDRFLAG(hi2c); - - int num_acks = 0; - - while (len > 0U) { - /* Wait until TXE flag is set */ - while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) { - /* Check if a NACK is detected */ - if (I2C_IsAcknowledgeFailed(hi2c)) { - goto nack; - } - - /* Check for the Timeout */ - if (Timeout != HAL_MAX_DELAY) { - if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) { - goto timeout; - } - } - } - - /* Write data to DR */ - hi2c->Instance->DR = *src++; - len--; - - /* Wait until BTF flag is set */ - while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET) { - /* Check if a NACK is detected */ - if (I2C_IsAcknowledgeFailed(hi2c)) { - goto nack; - } - - /* Check for the Timeout */ - if (Timeout != HAL_MAX_DELAY) { - if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) { - goto timeout; - } - } - } - ++num_acks; - } -nack: - - /* Generate Stop */ - if (stop) { - hi2c->Instance->CR1 |= I2C_CR1_STOP; - } - - return num_acks; - -timeout: - // timeout, release the bus cleanly - hi2c->Instance->CR1 |= I2C_CR1_STOP; - return -MP_ETIMEDOUT; + machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + return i2c_writeto(self->i2c, addr, src, len, stop); } #else @@ -423,22 +127,22 @@ typedef mp_machine_soft_i2c_obj_t machine_hard_i2c_obj_t; STATIC machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { #if defined(MICROPY_HW_I2C1_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C1_SCL, &MICROPY_HW_I2C1_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C2_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C2_SCL, &MICROPY_HW_I2C2_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C3_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C3_SCL, &MICROPY_HW_I2C3_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C4_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C4_SCL, &MICROPY_HW_I2C4_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif @@ -548,3 +252,5 @@ STATIC const mp_obj_type_t machine_hard_i2c_type = { .protocol = &machine_hard_i2c_p, .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict, }; + +#endif // MICROPY_HW_ENABLE_HW_I2C diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 16279d073d..c018d2de2a 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,7 @@ #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "lib/oofatfs/ff.h" +#include "lwip/init.h" #include "extmod/vfs.h" #include "extmod/vfs_fat.h" @@ -129,6 +130,7 @@ STATIC mp_obj_t pyb_main(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a } MP_DEFINE_CONST_FUN_OBJ_KW(pyb_main_obj, 1, pyb_main); +#if MICROPY_HW_ENABLE_STORAGE static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n" "# can run arbitrary Python, but best to keep it minimal\r\n" @@ -136,8 +138,10 @@ static const char fresh_boot_py[] = "import machine\r\n" "import pyb\r\n" "#pyb.main('main.py') # main script to run after this one\r\n" +#if MICROPY_HW_ENABLE_USB "#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device\r\n" "#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse\r\n" +#endif ; static const char fresh_main_py[] = @@ -190,7 +194,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { } // set label - f_setlabel(&vfs_fat->fatfs, "pybflash"); + f_setlabel(&vfs_fat->fatfs, MICROPY_HW_FLASH_FS_LABEL); // create empty main.py FIL fp; @@ -261,9 +265,10 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { return true; } +#endif #if MICROPY_HW_HAS_SDCARD -STATIC bool init_sdcard_fs(bool first_soft_reset) { +STATIC bool init_sdcard_fs(void) { bool first_part = true; for (int part_num = 1; part_num <= 4; ++part_num) { // create vfs object @@ -308,14 +313,14 @@ STATIC bool init_sdcard_fs(bool first_soft_reset) { } } - if (first_soft_reset) { - // use SD card as medium for the USB MSD - #if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB + if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) { + // if no USB MSC medium is selected then use the SD card pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_SDCARD; - #endif } + #endif - #if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB // only use SD card as current directory if that's what the USB medium is if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_SDCARD) #endif @@ -338,13 +343,14 @@ STATIC bool init_sdcard_fs(bool first_soft_reset) { } #endif +#if !MICROPY_HW_USES_BOOTLOADER STATIC uint update_reset_mode(uint reset_mode) { -#if MICROPY_HW_HAS_SWITCH + #if MICROPY_HW_HAS_SWITCH if (switch_get()) { // The original method used on the pyboard is appropriate if you have 2 // or more LEDs. -#if defined(MICROPY_HW_LED2) + #if defined(MICROPY_HW_LED2) for (uint i = 0; i < 3000; i++) { if (!switch_get()) { break; @@ -372,7 +378,7 @@ STATIC uint update_reset_mode(uint reset_mode) { } mp_hal_delay_ms(400); -#elif defined(MICROPY_HW_LED1) + #elif defined(MICROPY_HW_LED1) // For boards with only a single LED, we'll flash that LED the // appropriate number of times, with a pause between each one @@ -405,35 +411,71 @@ STATIC uint update_reset_mode(uint reset_mode) { } mp_hal_delay_ms(400); } -#else -#error Need a reset mode update method -#endif + #else + #error Need a reset mode update method + #endif } -#endif + #endif return reset_mode; } +#endif -int main(void) { - // TODO disable JTAG +void stm32_main(uint32_t reset_mode) { + // Enable caches and prefetch buffers - /* STM32F4xx HAL library initialization: - - Configure the Flash prefetch, instruction and Data caches - - Configure the Systick to generate an interrupt each 1 msec - - Set NVIC Group Priority to 4 - - Global MSP (MCU Support Package) initialization - */ - HAL_Init(); + #if defined(STM32F4) + + #if INSTRUCTION_CACHE_ENABLE + __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); + #endif + #if DATA_CACHE_ENABLE + __HAL_FLASH_DATA_CACHE_ENABLE(); + #endif + #if PREFETCH_ENABLE + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); + #endif + + #elif defined(STM32F7) || defined(STM32H7) + + #if ART_ACCLERATOR_ENABLE + __HAL_FLASH_ART_ENABLE(); + #endif + + SCB_EnableICache(); + SCB_EnableDCache(); + + #elif defined(STM32L4) + + #if !INSTRUCTION_CACHE_ENABLE + __HAL_FLASH_INSTRUCTION_CACHE_DISABLE(); + #endif + #if !DATA_CACHE_ENABLE + __HAL_FLASH_DATA_CACHE_DISABLE(); + #endif + #if PREFETCH_ENABLE + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); + #endif + + #endif + + #if __CORTEX_M >= 0x03 + // Set the priority grouping + NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); + #endif + + // SysTick is needed by HAL_RCC_ClockConfig (called in SystemClock_Config) + HAL_InitTick(TICK_INT_PRIORITY); // set the system clock to be HSE SystemClock_Config(); // enable GPIO clocks - __GPIOA_CLK_ENABLE(); - __GPIOB_CLK_ENABLE(); - __GPIOC_CLK_ENABLE(); - __GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) #if defined(__HAL_RCC_DTCMRAMEN_CLK_ENABLE) // The STM32F746 doesn't really have CCM memory, but it does have DTCM, // which behaves more or less like normal SRAM. @@ -442,8 +484,14 @@ int main(void) { // enable the CCM RAM __HAL_RCC_CCMDATARAMEN_CLK_ENABLE(); #endif + #elif defined(STM32H7) + // Enable D2 SRAM1/2/3 clocks. + __HAL_RCC_D2SRAM1_CLK_ENABLE(); + __HAL_RCC_D2SRAM2_CLK_ENABLE(); + __HAL_RCC_D2SRAM3_CLK_ENABLE(); #endif + #if defined(MICROPY_BOARD_EARLY_INIT) MICROPY_BOARD_EARLY_INIT(); #endif @@ -454,48 +502,46 @@ int main(void) { #endif pendsv_init(); led_init(); -#if MICROPY_HW_HAS_SWITCH + #if MICROPY_HW_HAS_SWITCH switch_init0(); -#endif - -#if defined(USE_DEVICE_MODE) - // default to internal flash being the usb medium - pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH; -#endif - - int first_soft_reset = true; + #endif + machine_init(); + #if MICROPY_HW_ENABLE_RTC + rtc_init_start(false); + #endif + spi_init0(); + #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C + i2c_init0(); + #endif + #if MICROPY_HW_HAS_SDCARD + sdcard_init(); + #endif + #if MICROPY_HW_ENABLE_STORAGE + storage_init(); + #endif + #if MICROPY_PY_LWIP + // lwIP doesn't allow to reinitialise itself by subsequent calls to this function + // because the system timeout list (next_timeout) is only ever reset by BSS clearing. + // So for now we only init the lwIP stack once on power-up. + lwip_init(); + #endif soft_reset: - // check if user switch held to select the reset mode -#if defined(MICROPY_HW_LED2) + #if defined(MICROPY_HW_LED2) led_state(1, 0); led_state(2, 1); -#else + #else led_state(1, 1); led_state(2, 0); -#endif + #endif led_state(3, 0); led_state(4, 0); - uint reset_mode = update_reset_mode(1); - machine_init(); - -#if MICROPY_HW_ENABLE_RTC - if (first_soft_reset) { - rtc_init_start(false); - } -#endif - - // more sub-system init -#if MICROPY_HW_HAS_SDCARD - if (first_soft_reset) { - sdcard_init(); - } -#endif - if (first_soft_reset) { - storage_init(); - } + #if !MICROPY_HW_USES_BOOTLOADER + // check if user switch held to select the reset mode + reset_mode = update_reset_mode(1); + #endif // Python threading init #if MICROPY_PY_THREAD @@ -511,6 +557,11 @@ soft_reset: // GC init gc_init(&_heap_start, &_heap_end); + #if MICROPY_ENABLE_PYSTACK + static mp_obj_t pystack[384]; + mp_pystack_init(pystack, &pystack[384]); + #endif + // MicroPython init mp_init(); mp_obj_list_init(mp_sys_path, 0); @@ -531,44 +582,51 @@ soft_reset: // Define MICROPY_HW_UART_REPL to be PYB_UART_6 and define // MICROPY_HW_UART_REPL_BAUD in your mpconfigboard.h file if you want a // REPL on a hardware UART as well as on USB VCP -#if defined(MICROPY_HW_UART_REPL) + #if defined(MICROPY_HW_UART_REPL) { mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL), MP_OBJ_NEW_SMALL_INT(MICROPY_HW_UART_REPL_BAUD), }; MP_STATE_PORT(pyb_stdio_uart) = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args); + uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), true); } -#else + #else MP_STATE_PORT(pyb_stdio_uart) = NULL; -#endif + #endif -#if MICROPY_HW_ENABLE_CAN + #if MICROPY_HW_ENABLE_CAN can_init0(); -#endif + #endif -#if MICROPY_HW_ENABLE_RNG - rng_init0(); -#endif - - i2c_init0(); - spi_init0(); + #if MICROPY_HW_ENABLE_USB pyb_usb_init0(); + #endif // Initialise the local flash filesystem. // Create it if needed, mount in on /flash, and set it as current dir. - bool mounted_flash = init_flash_fs(reset_mode); + bool mounted_flash = false; + #if MICROPY_HW_ENABLE_STORAGE + mounted_flash = init_flash_fs(reset_mode); + #endif bool mounted_sdcard = false; -#if MICROPY_HW_HAS_SDCARD + #if MICROPY_HW_HAS_SDCARD // if an SD card is present then mount it on /sd/ if (sdcard_is_present()) { // if there is a file in the flash called "SKIPSD", then we don't mount the SD card if (!mounted_flash || f_stat(&fs_user_mount_flash.fatfs, "/SKIPSD", NULL) != FR_OK) { - mounted_sdcard = init_sdcard_fs(first_soft_reset); + mounted_sdcard = init_sdcard_fs(); } } -#endif + #endif + + #if MICROPY_HW_ENABLE_USB + // if the SD card isn't used as the USB MSC medium then use the internal flash + if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) { + pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH; + } + #endif // set sys.path based on mounted filesystems (/sd is first so it can override /flash) if (mounted_sdcard) { @@ -600,12 +658,12 @@ soft_reset: } // turn boot-up LEDs off -#if !defined(MICROPY_HW_LED2) + #if !defined(MICROPY_HW_LED2) // If there is only one LED on the board then it's used to signal boot-up // and so we turn it off here. Otherwise LED(1) is used to indicate dirty // flash cache and so we shouldn't change its state. led_state(1, 0); -#endif + #endif led_state(2, 0); led_state(3, 0); led_state(4, 0); @@ -614,31 +672,29 @@ soft_reset: // or whose initialisation can be safely deferred until after running // boot.py. -#if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB // init USB device to default setting if it was not already configured if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) { pyb_usb_dev_init(USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, NULL); } -#endif + #endif -#if MICROPY_HW_HAS_MMA7660 + #if MICROPY_HW_HAS_MMA7660 // MMA accel: init and reset accel_init(); -#endif + #endif -#if MICROPY_HW_ENABLE_SERVO - // servo + #if MICROPY_HW_ENABLE_SERVO servo_init(); -#endif + #endif -#if MICROPY_HW_ENABLE_DAC - // DAC + #if MICROPY_HW_ENABLE_DAC dac_init(); -#endif + #endif -#if MICROPY_PY_NETWORK + #if MICROPY_PY_NETWORK mod_network_init(); -#endif + #endif // At this point everything is fully configured and initialised. @@ -680,20 +736,27 @@ soft_reset_exit: // soft reset + #if MICROPY_HW_ENABLE_STORAGE printf("PYB: sync filesystems\n"); storage_flush(); + #endif printf("PYB: soft reboot\n"); + #if MICROPY_PY_NETWORK + mod_network_deinit(); + #endif timer_deinit(); uart_deinit(); -#if MICROPY_HW_ENABLE_CAN + #if MICROPY_HW_ENABLE_CAN can_deinit(); -#endif + #endif + machine_deinit(); #if MICROPY_PY_THREAD pyb_thread_deinit(); #endif - first_soft_reset = false; + gc_sweep_all(); + goto soft_reset; } diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py index 3a8e22b386..d509d00c1c 100644 --- a/ports/stm32/make-stmconst.py +++ b/ports/stm32/make-stmconst.py @@ -244,8 +244,10 @@ def main(): print("") with open(args.qstr_filename, 'wt') as qstr_file: + print('#if MICROPY_PY_STM', file=qstr_file) for qstr in sorted(needed_qstrs): print('Q({})'.format(qstr), file=qstr_file) + print('#endif // MICROPY_PY_STM', file=qstr_file) with open(args.mpz_filename, 'wt') as mpz_file: for mpz in sorted(needed_mpzs): diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile new file mode 100644 index 0000000000..b9f439482e --- /dev/null +++ b/ports/stm32/mboot/Makefile @@ -0,0 +1,189 @@ +# Select the board to build for: if not given on the command line, +# then default to PYBV10. +BOARD ?= PYBV10 +ifeq ($(wildcard ../boards/$(BOARD)/.),) +$(error Invalid BOARD specified) +endif + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build-$(BOARD) + +include ../../../py/mkenv.mk +include ../boards/$(BOARD)/mpconfigboard.mk + +CMSIS_DIR=$(TOP)/lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Include +MCU_SERIES_UPPER = $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') +HAL_DIR=lib/stm32lib/STM32$(MCU_SERIES_UPPER)xx_HAL_Driver +USBDEV_DIR=usbdev +DFU=$(TOP)/tools/dfu.py +PYDFU ?= $(TOP)/tools/pydfu.py +DEVICE=0483:df11 +STFLASH ?= st-flash +OPENOCD ?= openocd +OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg + +CROSS_COMPILE = arm-none-eabi- + +INC += -I. +INC += -I.. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -I$(TOP)/lib/cmsis/inc +INC += -I$(CMSIS_DIR)/ +INC += -I$(TOP)/$(HAL_DIR)/Inc +INC += -I../$(USBDEV_DIR)/core/inc -I../$(USBDEV_DIR)/class/inc + +# Basic Cortex-M flags +CFLAGS_CORTEX_M = -mthumb + +# Options for particular MCU series +CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 +CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 + +CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) +CFLAGS += -D$(CMSIS_MCU) +CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) +CFLAGS += $(COPT) +CFLAGS += -I../boards/$(BOARD) +CFLAGS += -DSTM32_HAL_H='' +CFLAGS += -DBOARD_$(BOARD) +CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR) + +LDFLAGS = -nostdlib -L . -T stm32_generic.ld -Map=$(@:.elf=.map) --cref +LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +# Remove uncalled code from the final image. +CFLAGS += -fdata-sections -ffunction-sections +LDFLAGS += --gc-sections + +# Debugging/Optimization +ifeq ($(DEBUG), 1) +CFLAGS += -g -DPENDSV_DEBUG +COPT = -O0 +else +COPT += -Os -DNDEBUG +endif + +SRC_LIB = $(addprefix lib/,\ + libc/string0.c \ + ) + +SRC_C = \ + main.c \ + drivers/bus/softspi.c \ + drivers/bus/softqspi.c \ + drivers/memory/spiflash.c \ + ports/stm32/i2cslave.c \ + ports/stm32/qspi.c \ + ports/stm32/flashbdev.c \ + ports/stm32/spibdev.c \ + ports/stm32/usbd_conf.c \ + $(patsubst $(TOP)/%,%,$(wildcard $(TOP)/ports/stm32/boards/$(BOARD)/*.c)) + +SRC_O = \ + ports/stm32/boards/startup_stm32$(MCU_SERIES).o \ + ports/stm32/resethandler.o \ + +SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ + hal_cortex.c \ + hal_flash.c \ + hal_flash_ex.c \ + hal_pcd.c \ + hal_pcd_ex.c \ + ll_usb.c \ + ) + +SRC_USBDEV = $(addprefix ports/stm32/$(USBDEV_DIR)/,\ + core/src/usbd_core.c \ + core/src/usbd_ctlreq.c \ + core/src/usbd_ioreq.c \ + ) + +OBJ = +OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_O)) +OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o)) + +all: $(TOP)/lib/stm32lib/README.md $(BUILD)/firmware.dfu $(BUILD)/firmware.hex + +# For convenience, automatically fetch required submodules if they don't exist +$(TOP)/lib/stm32lib/README.md: + $(ECHO) "stm32lib submodule not found, fetching it now..." + (cd $(TOP) && git submodule update --init lib/stm32lib) + +.PHONY: deploy + +deploy: $(BUILD)/firmware.dfu + $(ECHO) "Writing $< to the board" + $(Q)$(PYTHON) $(PYDFU) -u $< + +FLASH_ADDR = 0x08000000 + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + $(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware.bin $@ + +$(BUILD)/firmware.hex: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O ihex $< $@ + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +######################################### + +vpath %.S . $(TOP) +$(BUILD)/%.o: %.S + $(ECHO) "CC $<" + $(Q)$(CC) $(CFLAGS) -c -o $@ $< + +vpath %.s . $(TOP) +$(BUILD)/%.o: %.s + $(ECHO) "AS $<" + $(Q)$(AS) -o $@ $< + +define compile_c +$(ECHO) "CC $<" +$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< +@# The following fixes the dependency file. +@# See http://make.paulandlesley.org/autodep.html for details. +@# Regex adjusted from the above to play better with Windows paths, etc. +@$(CP) $(@:.o=.d) $(@:.o=.P); \ + $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ + $(RM) -f $(@:.o=.d) +endef + +vpath %.c . $(TOP) +$(BUILD)/%.o: %.c + $(call compile_c) + +# $(sort $(var)) removes duplicates +# +# The net effect of this, is it causes the objects to depend on the +# object directories (but only for existence), and the object directories +# will be created if they don't exist. +OBJ_DIRS = $(sort $(dir $(OBJ))) +$(OBJ): | $(OBJ_DIRS) +$(OBJ_DIRS): + $(MKDIR) -p $@ + +clean: + $(RM) -rf $(BUILD) $(CLEAN_EXTRA) +.PHONY: clean + +########################################### + +$(BUILD)/main.o: $(BUILD)/genhdr/qstrdefs.generated.h + +$(BUILD)/genhdr/qstrdefs.generated.h: + $(MKDIR) -p $(BUILD)/genhdr + $(Q)echo "// empty" > $@ + +-include $(OBJ:.o=.P) diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md new file mode 100644 index 0000000000..2ff6101b44 --- /dev/null +++ b/ports/stm32/mboot/README.md @@ -0,0 +1,78 @@ +Mboot - MicroPython boot loader +=============================== + +Mboot is a custom bootloader for STM32 MCUs, and currently supports the +STM32F4xx and STM32F7xx families. It can provide a standard USB DFU interface +on either the FS or HS peripherals, as well as a sophisticated, custom I2C +interface. It fits in 16k of flash space. + +How to use +---------- + +1. Configure your board to use a boot loader by editing the mpconfigboard.mk + and mpconfigboard.h files. For example, for an F767 be sure to have these + lines in mpconfigboard.mk: + + LD_FILES = boards/stm32f767.ld boards/common_bl.ld + TEXT0_ADDR = 0x08008000 + + And this in mpconfigboard.h (recommended to put at the end of the file): + + // Bootloader configuration + #define MBOOT_I2C_PERIPH_ID 1 + #define MBOOT_I2C_SCL (pin_B8) + #define MBOOT_I2C_SDA (pin_B9) + #define MBOOT_I2C_ALTFUNC (4) + + To configure a pin to force entry into the boot loader the following + options can be used (with example configuration): + + #define MBOOT_BOOTPIN_PIN (pin_A0) + #define MBOOT_BOOTPIN_PULL (MP_HAL_PIN_PULL_UP) + #define MBOOT_BOOTPIN_ACTIVE (0) + + Mboot supports programming external SPI flash via the DFU and I2C + interfaces. SPI flash will be mapped to an address range. To + configure it use the following options (edit as needed): + + #define MBOOT_SPIFLASH_ADDR (0x80000000) + #define MBOOT_SPIFLASH_BYTE_SIZE (2 * 1024 * 1024) + #define MBOOT_SPIFLASH_LAYOUT "/0x80000000/64*32Kg" + #define MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE (32 / 4) + #define MBOOT_SPIFLASH_SPIFLASH (&spi_bdev.spiflash) + #define MBOOT_SPIFLASH_CONFIG (&spiflash_config) + + This assumes that the board declares and defines the relevant SPI flash + configuration structs, eg in the board-specific bdev.c file. The + `MBOOT_SPIFLASH2_LAYOUT` string will be seen by the USB DFU utility and + must describe the SPI flash layout. Note that the number of pages in + this layout description (the `64` above) cannot be larger than 99 (it + must fit in two digits) so the reported page size (the `32Kg` above) + must be made large enough so the number of pages fits in two digits. + Alternatively the layout can specify multiple sections like + `32*16Kg,32*16Kg`, in which case `MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE` + must be changed to `16 / 4` to match tho `16Kg` value. + + Mboot supports up to two external SPI flash devices. To configure the + second one use the same configuration names as above but with + `SPIFLASH2`, ie `MBOOT_SPIFLASH2_ADDR` etc. + +2. Build the board's main application firmware as usual. + +3. Build mboot via: + + $ cd mboot + $ make BOARD= + + That should produce a DFU file for mboot. It can be deployed using + USB DFU programming via (it will be placed at location 0x08000000): + + $ make BOARD= deploy + +4. Reset the board while holding USR until all 3 LEDs are lit (the 4th option in + the cycle) and then release USR. LED0 will then blink once per second to + indicate that it's in mboot + +5. Use either USB DFU or I2C to download firmware. The script mboot.py shows how + to communicate with the I2C boot loader interface. It should be run on a + pyboard connected via I2C to the target board. diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c new file mode 100644 index 0000000000..11053971bc --- /dev/null +++ b/ports/stm32/mboot/main.c @@ -0,0 +1,1341 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/mphal.h" +#include "extmod/crypto-algorithms/sha256.c" +#include "usbd_core.h" +#include "storage.h" +#include "i2cslave.h" + +// Using polling is about 10% faster than not using it (and using IRQ instead) +// This DFU code with polling runs in about 70% of the time of the ST bootloader +#define USE_USB_POLLING (1) + +// Using cache probably won't make it faster because we run at 48MHz, and best +// to keep the MCU config as minimal as possible. +#define USE_CACHE (0) + +// IRQ priorities (encoded values suitable for NVIC_SetPriority) +#define IRQ_PRI_SYSTICK (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0)) +#define IRQ_PRI_I2C (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0)) + +// Configure PLL to give a 48MHz CPU freq +#define CORE_PLL_FREQ (48000000) +#undef MICROPY_HW_CLK_PLLM +#undef MICROPY_HW_CLK_PLLN +#undef MICROPY_HW_CLK_PLLP +#undef MICROPY_HW_CLK_PLLQ +#define MICROPY_HW_CLK_PLLM (HSE_VALUE / 1000000) +#define MICROPY_HW_CLK_PLLN (192) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4) +#define MICROPY_HW_CLK_PLLQ (4) + +// Work out which USB device to use for the USB DFU interface +#if !defined(MICROPY_HW_USB_MAIN_DEV) +#if defined(MICROPY_HW_USB_FS) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID) +#elif defined(MICROPY_HW_USB_HS) && defined(MICROPY_HW_USB_HS_IN_FS) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) +#else +#error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use +#endif +#endif + +// These bits are used to detect valid application firmware at APPLICATION_ADDR +#define APP_VALIDITY_BITS (0x00000003) + +#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static void do_reset(void); + +static uint32_t get_le32(const uint8_t *b) { + return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24; +} + +void mp_hal_delay_us(mp_uint_t usec) { + // use a busy loop for the delay + // sys freq is always a multiple of 2MHz, so division here won't lose precision + const uint32_t ucount = CORE_PLL_FREQ / 2000000 * usec / 2; + for (uint32_t count = 0; ++count <= ucount;) { + } +} + +static volatile uint32_t systick_ms; + +void mp_hal_delay_ms(mp_uint_t ms) { + if (__get_PRIMASK() == 0) { + // IRQs enabled, use systick + if (ms != 0 && ms != (mp_uint_t)-1) { + ++ms; // account for the fact that systick_ms may roll over immediately + } + uint32_t start = systick_ms; + while (systick_ms - start < ms) { + __WFI(); + } + } else { + // IRQs disabled, so need to use a busy loop for the delay. + // To prevent possible overflow of the counter we use a double loop. + const uint32_t count_1ms = 16000000 / 8000; + for (uint32_t i = 0; i < ms; i++) { + for (volatile uint32_t count = 0; ++count <= count_1ms;) { + } + } + } +} + +// Needed by parts of the HAL +uint32_t HAL_GetTick(void) { + return systick_ms; +} + +// Needed by parts of the HAL +void HAL_Delay(uint32_t ms) { + mp_hal_delay_ms(ms); +} + +static void __fatal_error(const char *msg) { + NVIC_SystemReset(); + for (;;) { + } +} + +/******************************************************************************/ +// CLOCK + +#if defined(STM32F4) || defined(STM32F7) + +#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON) +#define CONFIG_RCC_PLLCFGR (0x24003010) + +#else +#error Unknown processor +#endif + +void SystemInit(void) { + // Set HSION bit + RCC->CR |= CONFIG_RCC_CR_1ST; + + // Reset CFGR register + RCC->CFGR = 0x00000000; + + // Reset HSEON, CSSON and PLLON bits + RCC->CR &= ~CONFIG_RCC_CR_2ND; + + // Reset PLLCFGR register + RCC->PLLCFGR = CONFIG_RCC_PLLCFGR; + + // Reset HSEBYP bit + RCC->CR &= (uint32_t)0xFFFBFFFF; + + // Disable all interrupts + RCC->CIR = 0x00000000; + + // Set location of vector table + SCB->VTOR = FLASH_BASE; + + // Enable 8-byte stack alignment for IRQ handlers, in accord with EABI + SCB->CCR |= SCB_CCR_STKALIGN_Msk; +} + +void systick_init(void) { + // Configure SysTick as 1ms ticker + SysTick_Config(SystemCoreClock / 1000); + NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK); +} + +void SystemClock_Config(void) { + // This function assumes that HSI is used as the system clock (see RCC->CFGR, SWS bits) + + // Enable Power Control clock + __HAL_RCC_PWR_CLK_ENABLE(); + + // Reduce power consumption + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + // Turn HSE on + __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) { + } + + // Disable PLL + __HAL_RCC_PLL_DISABLE(); + while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET) { + } + + // Configure PLL factors and source + RCC->PLLCFGR = + 1 << RCC_PLLCFGR_PLLSRC_Pos // HSE selected as PLL source + | MICROPY_HW_CLK_PLLM << RCC_PLLCFGR_PLLM_Pos + | MICROPY_HW_CLK_PLLN << RCC_PLLCFGR_PLLN_Pos + | ((MICROPY_HW_CLK_PLLP >> 1) - 1) << RCC_PLLCFGR_PLLP_Pos + | MICROPY_HW_CLK_PLLQ << RCC_PLLCFGR_PLLQ_Pos + #ifdef RCC_PLLCFGR_PLLR + | 2 << RCC_PLLCFGR_PLLR_Pos // default PLLR value of 2 + #endif + ; + + // Enable PLL + __HAL_RCC_PLL_ENABLE(); + while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET) { + } + + #if !defined(MICROPY_HW_FLASH_LATENCY) + #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_1 + #endif + + // Increase latency before changing clock + if (MICROPY_HW_FLASH_LATENCY > (FLASH->ACR & FLASH_ACR_LATENCY)) { + __HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY); + } + + // Configure AHB divider + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1); + + // Configure SYSCLK source from PLL + __HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK); + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK) { + } + + // Decrease latency after changing clock + if (MICROPY_HW_FLASH_LATENCY < (FLASH->ACR & FLASH_ACR_LATENCY)) { + __HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY); + } + + // Set APB clock dividers + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_HCLK_DIV4); + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, RCC_HCLK_DIV2 << 3); + + // Update clock value and reconfigure systick now that the frequency changed + SystemCoreClock = CORE_PLL_FREQ; + systick_init(); + + #if defined(STM32F7) + // The DFU bootloader changes the clocksource register from its default power + // on reset value, so we set it back here, so the clocksources are the same + // whether we were started from DFU or from a power on reset. + RCC->DCKCFGR2 = 0; + #endif +} + +// Needed by HAL_PCD_IRQHandler +uint32_t HAL_RCC_GetHCLKFreq(void) { + return SystemCoreClock; +} + +/******************************************************************************/ +// GPIO + +void mp_hal_pin_config(mp_hal_pin_obj_t port_pin, uint32_t mode, uint32_t pull, uint32_t alt) { + GPIO_TypeDef *gpio = (GPIO_TypeDef*)(port_pin & ~0xf); + + // Enable the GPIO peripheral clock + uint32_t en_bit = RCC_AHB1ENR_GPIOAEN_Pos + ((uintptr_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE); + RCC->AHB1ENR |= 1 << en_bit; + volatile uint32_t tmp = RCC->AHB1ENR; // Delay after enabling clock + (void)tmp; + + // Configure the pin + uint32_t pin = port_pin & 0xf; + gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin)); + gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin); + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (2 << (2 * pin)); // full speed + gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin)); + gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); +} + +void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) { + GPIO_TypeDef *gpio = (GPIO_TypeDef*)(port_pin & ~0xf); + uint32_t pin = port_pin & 0xf; + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin)); +} + +/******************************************************************************/ +// LED + +#define LED0 MICROPY_HW_LED1 +#define LED1 MICROPY_HW_LED2 +#define LED2 MICROPY_HW_LED3 + +void led_init(void) { + mp_hal_pin_output(LED0); + mp_hal_pin_output(LED1); + mp_hal_pin_output(LED2); +} + +void led_state(int led, int val) { + if (led == 1) { + led = LED0; + } + if (val) { + MICROPY_HW_LED_ON(led); + } else { + MICROPY_HW_LED_OFF(led); + } +} + +/******************************************************************************/ +// USR BUTTON + +static void usrbtn_init(void) { + mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0); +} + +static int usrbtn_state(void) { + return mp_hal_pin_read(MICROPY_HW_USRSW_PIN) == MICROPY_HW_USRSW_PRESSED; +} + +/******************************************************************************/ +// FLASH + +#ifndef MBOOT_SPIFLASH_LAYOUT +#define MBOOT_SPIFLASH_LAYOUT "" +#endif + +#ifndef MBOOT_SPIFLASH2_LAYOUT +#define MBOOT_SPIFLASH2_LAYOUT "" +#endif + +typedef struct { + uint32_t base_address; + uint32_t sector_size; + uint32_t sector_count; +} flash_layout_t; + +#if defined(STM32F7) +// FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to +// FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7 +#define FLASH_FLAG_PGSERR FLASH_FLAG_ERSERR +#endif + +#if defined(STM32F4) \ + || defined(STM32F722xx) \ + || defined(STM32F723xx) \ + || defined(STM32F732xx) \ + || defined(STM32F733xx) + +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT + +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x04000, 4 }, + { 0x08010000, 0x10000, 1 }, + { 0x08020000, 0x20000, 3 }, + #if defined(FLASH_SECTOR_8) + { 0x08080000, 0x20000, 4 }, + #endif + #if defined(FLASH_SECTOR_12) + { 0x08100000, 0x04000, 4 }, + { 0x08110000, 0x10000, 1 }, + { 0x08120000, 0x20000, 7 }, + #endif +}; + +#elif defined(STM32F767xx) + +#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/04*032Kg,01*128Kg,07*256Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT + +// This is for dual-bank mode disabled +static const flash_layout_t flash_layout[] = { + { 0x08000000, 0x08000, 4 }, + { 0x08020000, 0x20000, 1 }, + { 0x08040000, 0x40000, 7 }, +}; + +#endif + +static uint32_t flash_get_sector_index(uint32_t addr) { + if (addr >= flash_layout[0].base_address) { + uint32_t sector_index = 0; + for (int i = 0; i < MP_ARRAY_SIZE(flash_layout); ++i) { + for (int j = 0; j < flash_layout[i].sector_count; ++j) { + uint32_t sector_start_next = flash_layout[i].base_address + + (j + 1) * flash_layout[i].sector_size; + if (addr < sector_start_next) { + return sector_index; + } + ++sector_index; + } + } + } + return 0; +} + +static int flash_mass_erase(void) { + // TODO + return -1; +} + +static int flash_page_erase(uint32_t addr) { + uint32_t sector = flash_get_sector_index(addr); + if (sector == 0) { + // Don't allow to erase the sector with this bootloader in it + return -1; + } + + HAL_FLASH_Unlock(); + + // Clear pending flags (if any) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | + FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); + + // erase the sector(s) + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = TYPEERASE_SECTORS; + EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + EraseInitStruct.Sector = sector; + EraseInitStruct.NbSectors = 1; + + uint32_t SectorError = 0; + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { + // error occurred during sector erase + return -1; + } + + // Check the erase set bits to 1, at least for the first 256 bytes + for (int i = 0; i < 64; ++i) { + if (((volatile uint32_t*)addr)[i] != 0xffffffff) { + return -2; + } + } + + return 0; +} + +static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) { + if (addr >= flash_layout[0].base_address && addr < flash_layout[0].base_address + flash_layout[0].sector_size) { + // Don't allow to write the sector with this bootloader in it + return -1; + } + + const uint32_t *src = (const uint32_t*)src8; + size_t num_word32 = (len + 3) / 4; + HAL_FLASH_Unlock(); + // program the flash word by word + for (size_t i = 0; i < num_word32; i++) { + if (HAL_FLASH_Program(TYPEPROGRAM_WORD, addr, *src) != HAL_OK) { + return -1; + } + addr += 4; + src += 1; + } + + // TODO verify data + + return 0; +} + +/******************************************************************************/ +// Writable address space interface + +static int do_mass_erase(void) { + // TODO + return flash_mass_erase(); +} + +#if defined(MBOOT_SPIFLASH_ADDR) || defined(MBOOT_SPIFLASH2_ADDR) +static int spiflash_page_erase(mp_spiflash_t *spif, uint32_t addr, uint32_t n_blocks) { + for (int i = 0; i < n_blocks; ++i) { + int ret = mp_spiflash_erase_block(spif, addr); + if (ret != 0) { + return ret; + } + addr += MP_SPIFLASH_ERASE_BLOCK_SIZE; + } + return 0; +} +#endif + +static int do_page_erase(uint32_t addr) { + led_state(LED0, 1); + + #if defined(MBOOT_SPIFLASH_ADDR) + if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + return spiflash_page_erase(MBOOT_SPIFLASH_SPIFLASH, + addr - MBOOT_SPIFLASH_ADDR, MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE); + } + #endif + + #if defined(MBOOT_SPIFLASH2_ADDR) + if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + return spiflash_page_erase(MBOOT_SPIFLASH2_SPIFLASH, + addr - MBOOT_SPIFLASH2_ADDR, MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE); + } + #endif + + return flash_page_erase(addr); +} + +static void do_read(uint32_t addr, int len, uint8_t *buf) { + #if defined(MBOOT_SPIFLASH_ADDR) + if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, buf); + return; + } + #endif + #if defined(MBOOT_SPIFLASH2_ADDR) + if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + mp_spiflash_read(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, buf); + return; + } + #endif + + // Other addresses, just read directly from memory + memcpy(buf, (void*)addr, len); +} + +static int do_write(uint32_t addr, const uint8_t *src8, size_t len) { + static uint32_t led_tog = 0; + led_state(LED0, (led_tog++) & 4); + + #if defined(MBOOT_SPIFLASH_ADDR) + if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) { + return mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, src8); + } + #endif + + #if defined(MBOOT_SPIFLASH2_ADDR) + if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) { + return mp_spiflash_write(MBOOT_SPIFLASH2_SPIFLASH, addr - MBOOT_SPIFLASH2_ADDR, len, src8); + } + #endif + + return flash_write(addr, src8, len); +} + +/******************************************************************************/ +// I2C slave interface + +#if defined(MBOOT_I2C_SCL) + +#define PASTE2(a, b) a ## b +#define PASTE3(a, b, c) a ## b ## c +#define EVAL_PASTE2(a, b) PASTE2(a, b) +#define EVAL_PASTE3(a, b, c) PASTE3(a, b, c) + +#define MBOOT_I2Cx EVAL_PASTE2(I2C, MBOOT_I2C_PERIPH_ID) +#define I2Cx_EV_IRQn EVAL_PASTE3(I2C, MBOOT_I2C_PERIPH_ID, _EV_IRQn) +#define I2Cx_EV_IRQHandler EVAL_PASTE3(I2C, MBOOT_I2C_PERIPH_ID, _EV_IRQHandler) + +#define I2C_CMD_BUF_LEN (129) + +enum { + I2C_CMD_ECHO = 1, + I2C_CMD_GETID, // () -> u8*12 unique id, ASCIIZ mcu name, ASCIIZ board name + I2C_CMD_GETCAPS, // not implemented + I2C_CMD_RESET, // () -> () + I2C_CMD_CONFIG, // not implemented + I2C_CMD_GETLAYOUT, // () -> ASCII string + I2C_CMD_MASSERASE, // () -> () + I2C_CMD_PAGEERASE, // le32 -> () + I2C_CMD_SETRDADDR, // le32 -> () + I2C_CMD_SETWRADDR, // le32 -> () + I2C_CMD_READ, // u8 -> bytes + I2C_CMD_WRITE, // bytes -> () + I2C_CMD_COPY, // not implemented + I2C_CMD_CALCHASH, // le32 -> u8*32 + I2C_CMD_MARKVALID, // () -> () +}; + +typedef struct _i2c_obj_t { + volatile bool cmd_send_arg; + volatile bool cmd_arg_sent; + volatile int cmd_arg; + volatile uint32_t cmd_rdaddr; + volatile uint32_t cmd_wraddr; + volatile uint16_t cmd_buf_pos; + uint8_t cmd_buf[I2C_CMD_BUF_LEN]; +} i2c_obj_t; + +static i2c_obj_t i2c_obj; + +void i2c_init(int addr) { + i2c_obj.cmd_send_arg = false; + + mp_hal_pin_config(MBOOT_I2C_SCL, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, MBOOT_I2C_ALTFUNC); + mp_hal_pin_config(MBOOT_I2C_SDA, MP_HAL_PIN_MODE_ALT_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, MBOOT_I2C_ALTFUNC); + + i2c_slave_init(MBOOT_I2Cx, I2Cx_EV_IRQn, IRQ_PRI_I2C, addr); +} + +int i2c_slave_process_addr_match(int rw) { + if (i2c_obj.cmd_arg_sent) { + i2c_obj.cmd_send_arg = false; + } + i2c_obj.cmd_buf_pos = 0; + return 0; // ACK +} + +int i2c_slave_process_rx_byte(uint8_t val) { + if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) { + i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++] = val; + } + return 0; // ACK +} + +void i2c_slave_process_rx_end(void) { + if (i2c_obj.cmd_buf_pos == 0) { + return; + } + + int len = i2c_obj.cmd_buf_pos - 1; + uint8_t *buf = i2c_obj.cmd_buf; + + if (buf[0] == I2C_CMD_ECHO) { + ++len; + } else if (buf[0] == I2C_CMD_GETID && len == 0) { + memcpy(buf, (uint8_t*)MP_HAL_UNIQUE_ID_ADDRESS, 12); + memcpy(buf + 12, MICROPY_HW_MCU_NAME, sizeof(MICROPY_HW_MCU_NAME)); + memcpy(buf + 12 + sizeof(MICROPY_HW_MCU_NAME), MICROPY_HW_BOARD_NAME, sizeof(MICROPY_HW_BOARD_NAME) - 1); + len = 12 + sizeof(MICROPY_HW_MCU_NAME) + sizeof(MICROPY_HW_BOARD_NAME) - 1; + } else if (buf[0] == I2C_CMD_RESET && len == 0) { + do_reset(); + } else if (buf[0] == I2C_CMD_GETLAYOUT && len == 0) { + len = strlen(FLASH_LAYOUT_STR); + memcpy(buf, FLASH_LAYOUT_STR, len); + } else if (buf[0] == I2C_CMD_MASSERASE && len == 0) { + len = do_mass_erase(); + } else if (buf[0] == I2C_CMD_PAGEERASE && len == 4) { + len = do_page_erase(get_le32(buf + 1)); + } else if (buf[0] == I2C_CMD_SETRDADDR && len == 4) { + i2c_obj.cmd_rdaddr = get_le32(buf + 1); + len = 0; + } else if (buf[0] == I2C_CMD_SETWRADDR && len == 4) { + i2c_obj.cmd_wraddr = get_le32(buf + 1); + len = 0; + } else if (buf[0] == I2C_CMD_READ && len == 1) { + len = buf[1]; + if (len > I2C_CMD_BUF_LEN) { + len = I2C_CMD_BUF_LEN; + } + do_read(i2c_obj.cmd_rdaddr, len, buf); + i2c_obj.cmd_rdaddr += len; + } else if (buf[0] == I2C_CMD_WRITE) { + if (i2c_obj.cmd_wraddr == APPLICATION_ADDR) { + // Mark the 2 lower bits to indicate invalid app firmware + buf[1] |= APP_VALIDITY_BITS; + } + int ret = do_write(i2c_obj.cmd_wraddr, buf + 1, len); + if (ret < 0) { + len = ret; + } else { + i2c_obj.cmd_wraddr += len; + len = 0; + } + } else if (buf[0] == I2C_CMD_CALCHASH && len == 4) { + uint32_t hashlen = get_le32(buf + 1); + static CRYAL_SHA256_CTX ctx; + sha256_init(&ctx); + sha256_update(&ctx, (const void*)i2c_obj.cmd_rdaddr, hashlen); + i2c_obj.cmd_rdaddr += hashlen; + sha256_final(&ctx, buf); + len = 32; + } else if (buf[0] == I2C_CMD_MARKVALID && len == 0) { + uint32_t buf; + buf = *(volatile uint32_t*)APPLICATION_ADDR; + if ((buf & APP_VALIDITY_BITS) != APP_VALIDITY_BITS) { + len = -1; + } else { + buf &= ~APP_VALIDITY_BITS; + int ret = do_write(APPLICATION_ADDR, (void*)&buf, 4); + if (ret < 0) { + len = ret; + } else { + buf = *(volatile uint32_t*)APPLICATION_ADDR; + if ((buf & APP_VALIDITY_BITS) != 0) { + len = -2; + } else { + len = 0; + } + } + } + } else { + len = -127; + } + i2c_obj.cmd_arg = len; + i2c_obj.cmd_send_arg = true; + i2c_obj.cmd_arg_sent = false; +} + +uint8_t i2c_slave_process_tx_byte(void) { + if (i2c_obj.cmd_send_arg) { + i2c_obj.cmd_arg_sent = true; + return i2c_obj.cmd_arg; + } else if (i2c_obj.cmd_buf_pos < sizeof(i2c_obj.cmd_buf)) { + return i2c_obj.cmd_buf[i2c_obj.cmd_buf_pos++]; + } else { + return 0; + } +} + +#endif // defined(MBOOT_I2C_SCL) + +/******************************************************************************/ +// DFU + +#define DFU_XFER_SIZE (2048) + +enum { + DFU_DNLOAD = 1, + DFU_UPLOAD = 2, + DFU_GETSTATUS = 3, + DFU_CLRSTATUS = 4, + DFU_ABORT = 6, +}; + +enum { + DFU_STATUS_IDLE = 2, + DFU_STATUS_BUSY = 4, + DFU_STATUS_DNLOAD_IDLE = 5, + DFU_STATUS_MANIFEST = 7, + DFU_STATUS_UPLOAD_IDLE = 9, + DFU_STATUS_ERROR = 0xa, +}; + +enum { + DFU_CMD_NONE = 0, + DFU_CMD_EXIT = 1, + DFU_CMD_UPLOAD = 7, + DFU_CMD_DNLOAD = 8, +}; + +typedef struct _dfu_state_t { + int status; + int cmd; + uint16_t wBlockNum; + uint16_t wLength; + uint32_t addr; + uint8_t buf[DFU_XFER_SIZE] __attribute__((aligned(4))); +} dfu_state_t; + +static dfu_state_t dfu_state; + +static void dfu_init(void) { + dfu_state.status = DFU_STATUS_IDLE; + dfu_state.cmd = DFU_CMD_NONE; + dfu_state.addr = 0x08000000; +} + +static int dfu_process_dnload(void) { + int ret = -1; + if (dfu_state.wBlockNum == 0) { + // download control commands + if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x41) { + if (dfu_state.wLength == 1) { + // mass erase + ret = do_mass_erase(); + } else if (dfu_state.wLength == 5) { + // erase page + ret = do_page_erase(get_le32(&dfu_state.buf[1])); + } + } else if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x21) { + if (dfu_state.wLength == 5) { + // set address + dfu_state.addr = get_le32(&dfu_state.buf[1]); + ret = 0; + } + } + } else if (dfu_state.wBlockNum > 1) { + // write data to memory + ret = do_write(dfu_state.addr, dfu_state.buf, dfu_state.wLength); + } + if (ret == 0) { + return DFU_STATUS_DNLOAD_IDLE; + } else { + return DFU_STATUS_ERROR; + } +} + +static void dfu_handle_rx(int cmd, int arg, int len, const void *buf) { + if (cmd == DFU_CLRSTATUS) { + // clear status + dfu_state.status = DFU_STATUS_IDLE; + dfu_state.cmd = DFU_CMD_NONE; + } else if (cmd == DFU_ABORT) { + // clear status + dfu_state.status = DFU_STATUS_IDLE; + dfu_state.cmd = DFU_CMD_NONE; + } else if (cmd == DFU_DNLOAD) { + if (len == 0) { + // exit DFU + dfu_state.cmd = DFU_CMD_EXIT; + } else { + // download + dfu_state.cmd = DFU_CMD_DNLOAD; + dfu_state.wBlockNum = arg; + dfu_state.wLength = len; + memcpy(dfu_state.buf, buf, len); + } + } +} + +static void dfu_process(void) { + if (dfu_state.status == DFU_STATUS_MANIFEST) { + do_reset(); + } + + if (dfu_state.status == DFU_STATUS_BUSY) { + if (dfu_state.cmd == DFU_CMD_DNLOAD) { + dfu_state.cmd = DFU_CMD_NONE; + dfu_state.status = dfu_process_dnload(); + } + } +} + +static int dfu_handle_tx(int cmd, int arg, int len, uint8_t *buf, int max_len) { + if (cmd == DFU_UPLOAD) { + if (arg >= 2) { + dfu_state.cmd = DFU_CMD_UPLOAD; + uint32_t addr = (arg - 2) * max_len + dfu_state.addr; + do_read(addr, len, buf); + return len; + } + } else if (cmd == DFU_GETSTATUS && len == 6) { + // execute command and get status + switch (dfu_state.cmd) { + case DFU_CMD_NONE: + break; + case DFU_CMD_EXIT: + dfu_state.status = DFU_STATUS_MANIFEST; + break; + case DFU_CMD_UPLOAD: + dfu_state.status = DFU_STATUS_UPLOAD_IDLE; + break; + case DFU_CMD_DNLOAD: + dfu_state.status = DFU_STATUS_BUSY; + break; + } + buf[0] = 0; + buf[1] = dfu_state.cmd; // TODO is this correct? + buf[2] = 0; + buf[3] = 0; + buf[4] = dfu_state.status; + buf[5] = 0; + return 6; + } + return -1; +} + +/******************************************************************************/ +// USB + +#define USB_XFER_SIZE (DFU_XFER_SIZE) + +enum { + USB_PHY_FS_ID = 0, + USB_PHY_HS_ID = 1, +}; + +typedef struct _pyb_usbdd_obj_t { + bool started; + bool tx_pending; + USBD_HandleTypeDef hUSBDDevice; + + uint8_t bRequest; + uint16_t wValue; + uint16_t wLength; + __ALIGN_BEGIN uint8_t rx_buf[USB_XFER_SIZE] __ALIGN_END; + __ALIGN_BEGIN uint8_t tx_buf[USB_XFER_SIZE] __ALIGN_END; + + // RAM to hold the current descriptors, which we configure on the fly + __ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END; + __ALIGN_BEGIN uint8_t usbd_str_desc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; +} pyb_usbdd_obj_t; + +#define USBD_LANGID_STRING (0x409) + +__ALIGN_BEGIN static const uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { + USB_LEN_LANGID_STR_DESC, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING), +}; + +static const uint8_t dev_descr[0x12] = "\x12\x01\x00\x01\x00\x00\x00\x40\x83\x04\x11\xdf\x00\x22\x01\x02\x03\x01"; + +// This may be modified by USBD_GetDescriptor +static uint8_t cfg_descr[9 + 9 + 9] = + "\x09\x02\x1b\x00\x01\x01\x00\xc0\x32" + "\x09\x04\x00\x00\x00\xfe\x01\x02\x04" + "\x09\x21\x0b\xff\x00\x00\x08\x1a\x01" // \x00\x08 goes with USB_XFER_SIZE +; + +static uint8_t *pyb_usbdd_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { + *length = USB_LEN_DEV_DESC; + return (uint8_t*)dev_descr; +} + +static char get_hex_char(int val) { + val &= 0xf; + if (val <= 9) { + return '0' + val; + } else { + return 'A' + val - 10; + } +} + +static void format_hex(char *buf, int val) { + buf[0] = get_hex_char(val >> 4); + buf[1] = get_hex_char(val); +} + +static uint8_t *pyb_usbdd_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + uint8_t *str_desc = self->usbd_str_desc; + switch (idx) { + case USBD_IDX_LANGID_STR: + *length = sizeof(USBD_LangIDDesc); + return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf + + case USBD_IDX_MFC_STR: + USBD_GetString((uint8_t*)"USBDevice Manuf", str_desc, length); + return str_desc; + + case USBD_IDX_PRODUCT_STR: + USBD_GetString((uint8_t*)"USBDevice Product", str_desc, length); + return str_desc; + + case USBD_IDX_SERIAL_STR: { + // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf + // says that the serial number has to be at least 12 digits long and that + // the last 12 digits need to be unique. It also stipulates that the valid + // character set is that of upper-case hexadecimal digits. + // + // The onboard DFU bootloader produces a 12-digit serial number based on + // the 96-bit unique ID, so for consistency we go with this algorithm. + // You can see the serial number if you do: + // + // dfu-util -l + // + // See: https://my.st.com/52d187b7 for the algorithim used. + uint8_t *id = (uint8_t*)MP_HAL_UNIQUE_ID_ADDRESS; + char serial_buf[16]; + format_hex(&serial_buf[0], id[11]); + format_hex(&serial_buf[2], id[10] + id[2]); + format_hex(&serial_buf[4], id[9]); + format_hex(&serial_buf[6], id[8] + id[0]); + format_hex(&serial_buf[8], id[7]); + format_hex(&serial_buf[10], id[6]); + serial_buf[12] = '\0'; + + USBD_GetString((uint8_t*)serial_buf, str_desc, length); + return str_desc; + } + + case USBD_IDX_CONFIG_STR: + USBD_GetString((uint8_t*)FLASH_LAYOUT_STR, str_desc, length); + return str_desc; + + default: + return NULL; + } +} + +static const USBD_DescriptorsTypeDef pyb_usbdd_descriptors = { + pyb_usbdd_DeviceDescriptor, + pyb_usbdd_StrDescriptor, +}; + +static uint8_t pyb_usbdd_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + return USBD_OK; +} + +static uint8_t pyb_usbdd_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + return USBD_OK; +} + +static uint8_t pyb_usbdd_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + self->bRequest = req->bRequest; + self->wValue = req->wValue; + self->wLength = req->wLength; + if (req->bmRequest == 0x21) { + // host-to-device request + if (req->wLength == 0) { + // no data, process command straightaway + dfu_handle_rx(self->bRequest, self->wValue, 0, NULL); + } else { + // have data, prepare to receive it + USBD_CtlPrepareRx(pdev, self->rx_buf, req->wLength); + } + } else if (req->bmRequest == 0xa1) { + // device-to-host request + int len = dfu_handle_tx(self->bRequest, self->wValue, self->wLength, self->tx_buf, USB_XFER_SIZE); + if (len >= 0) { + self->tx_pending = true; + USBD_CtlSendData(&self->hUSBDDevice, self->tx_buf, len); + } + } + return USBD_OK; +} + +static uint8_t pyb_usbdd_EP0_TxSent(USBD_HandleTypeDef *pdev) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + self->tx_pending = false; + #if !USE_USB_POLLING + // Process now that we have sent a response + dfu_process(); + #endif + return USBD_OK; +} + +static uint8_t pyb_usbdd_EP0_RxReady(USBD_HandleTypeDef *pdev) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + dfu_handle_rx(self->bRequest, self->wValue, self->wLength, self->rx_buf); + return USBD_OK; +} + +static uint8_t *pyb_usbdd_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { + *length = sizeof(cfg_descr); + return (uint8_t*)cfg_descr; +} + +// this is used only in high-speed mode, which we don't support +static uint8_t *pyb_usbdd_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { + pyb_usbdd_obj_t *self = (pyb_usbdd_obj_t*)pdev->pClassData; + (void)self; + /* + *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc); + return USBD_CDC_MSC_HID_DeviceQualifierDesc; + */ + *length = 0; + return NULL; +} + +static const USBD_ClassTypeDef pyb_usbdd_class = { + pyb_usbdd_Init, + pyb_usbdd_DeInit, + pyb_usbdd_Setup, + pyb_usbdd_EP0_TxSent, + pyb_usbdd_EP0_RxReady, + NULL, // pyb_usbdd_DataIn, + NULL, // pyb_usbdd_DataOut, + NULL, // SOF + NULL, // IsoINIncomplete + NULL, // IsoOUTIncomplete + pyb_usbdd_GetCfgDesc, + pyb_usbdd_GetCfgDesc, + pyb_usbdd_GetCfgDesc, + pyb_usbdd_GetDeviceQualifierDescriptor, +}; + +static pyb_usbdd_obj_t pyb_usbdd; + +static void pyb_usbdd_init(pyb_usbdd_obj_t *self, int phy_id) { + self->started = false; + USBD_HandleTypeDef *usbd = &self->hUSBDDevice; + usbd->id = phy_id; + usbd->dev_state = USBD_STATE_DEFAULT; + usbd->pDesc = (USBD_DescriptorsTypeDef*)&pyb_usbdd_descriptors; + usbd->pClass = &pyb_usbdd_class; + usbd->pClassData = self; +} + +static void pyb_usbdd_start(pyb_usbdd_obj_t *self) { + if (!self->started) { + USBD_LL_Init(&self->hUSBDDevice, 0); + USBD_LL_Start(&self->hUSBDDevice); + self->started = true; + } +} + +static void pyb_usbdd_stop(pyb_usbdd_obj_t *self) { + if (self->started) { + USBD_Stop(&self->hUSBDDevice); + self->started = false; + } +} + +static int pyb_usbdd_shutdown(void) { + pyb_usbdd_stop(&pyb_usbdd); + return 0; +} + +/******************************************************************************/ +// main + +#define RESET_MODE_NUM_STATES (4) +#define RESET_MODE_TIMEOUT_CYCLES (8) +#define RESET_MODE_LED_STATES 0x7421 + +static int get_reset_mode(void) { + usrbtn_init(); + int reset_mode = 1; + if (usrbtn_state()) { + // Cycle through reset modes while USR is held + // Timeout is roughly 20s, where reset_mode=1 + systick_init(); + led_init(); + reset_mode = 0; + for (int i = 0; i < (RESET_MODE_NUM_STATES * RESET_MODE_TIMEOUT_CYCLES + 1) * 32; i++) { + if (i % 32 == 0) { + if (++reset_mode > RESET_MODE_NUM_STATES) { + reset_mode = 1; + } + uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4); + led_state(LED0, l & 1); + led_state(LED1, l & 2); + led_state(LED2, l & 4); + } + if (!usrbtn_state()) { + break; + } + mp_hal_delay_ms(19); + } + // Flash the selected reset mode + for (int i = 0; i < 6; i++) { + led_state(LED0, 0); + led_state(LED1, 0); + led_state(LED2, 0); + mp_hal_delay_ms(50); + uint8_t l = RESET_MODE_LED_STATES >> ((reset_mode - 1) * 4); + led_state(LED0, l & 1); + led_state(LED1, l & 2); + led_state(LED2, l & 4); + mp_hal_delay_ms(50); + } + mp_hal_delay_ms(300); + } + return reset_mode; +} + +static void do_reset(void) { + led_state(LED0, 0); + led_state(LED1, 0); + led_state(LED2, 0); + mp_hal_delay_ms(50); + pyb_usbdd_shutdown(); + #if defined(MBOOT_I2C_SCL) + i2c_slave_shutdown(MBOOT_I2Cx, I2Cx_EV_IRQn); + #endif + mp_hal_delay_ms(50); + NVIC_SystemReset(); +} + +uint32_t SystemCoreClock; + +extern PCD_HandleTypeDef pcd_fs_handle; +extern PCD_HandleTypeDef pcd_hs_handle; + +void stm32_main(int initial_r0) { + #if defined(STM32F4) + #if INSTRUCTION_CACHE_ENABLE + __HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); + #endif + #if DATA_CACHE_ENABLE + __HAL_FLASH_DATA_CACHE_ENABLE(); + #endif + #if PREFETCH_ENABLE + __HAL_FLASH_PREFETCH_BUFFER_ENABLE(); + #endif + #elif defined(STM32F7) + #if ART_ACCLERATOR_ENABLE + __HAL_FLASH_ART_ENABLE(); + #endif + #endif + + NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); + + #if USE_CACHE && defined(STM32F7) + SCB_EnableICache(); + SCB_EnableDCache(); + #endif + + #ifdef MBOOT_BOOTPIN_PIN + mp_hal_pin_config(MBOOT_BOOTPIN_PIN, MP_HAL_PIN_MODE_INPUT, MBOOT_BOOTPIN_PULL, 0); + if (mp_hal_pin_read(MBOOT_BOOTPIN_PIN) == MBOOT_BOOTPIN_ACTIVE) { + goto enter_bootloader; + } + #endif + + if ((initial_r0 & 0xffffff00) == 0x70ad0000) { + goto enter_bootloader; + } + + // MCU starts up with 16MHz HSI + SystemCoreClock = 16000000; + + int reset_mode = get_reset_mode(); + uint32_t msp = *(volatile uint32_t*)APPLICATION_ADDR; + if (reset_mode != 4 && (msp & APP_VALIDITY_BITS) == 0) { + // not DFU mode so jump to application, passing through reset_mode + // undo our DFU settings + // TODO probably should disable all IRQ sources first + #if USE_CACHE && defined(STM32F7) + SCB_DisableICache(); + SCB_DisableDCache(); + #endif + __set_MSP(msp); + ((void (*)(uint32_t)) *((volatile uint32_t*)(APPLICATION_ADDR + 4)))(reset_mode); + } + +enter_bootloader: + + // Init subsystems (get_reset_mode() may call these, calling them again is ok) + led_init(); + + // set the system clock to be HSE + SystemClock_Config(); + + #if USE_USB_POLLING + // irqs with a priority value greater or equal to "pri" will be disabled + // "pri" should be between 1 and 15 inclusive + uint32_t pri = 2; + pri <<= (8 - __NVIC_PRIO_BITS); + __ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory"); + #endif + + #if defined(MBOOT_SPIFLASH_ADDR) + MBOOT_SPIFLASH_SPIFLASH->config = MBOOT_SPIFLASH_CONFIG; + mp_spiflash_init(MBOOT_SPIFLASH_SPIFLASH); + #endif + + #if defined(MBOOT_SPIFLASH2_ADDR) + MBOOT_SPIFLASH2_SPIFLASH->config = MBOOT_SPIFLASH2_CONFIG; + mp_spiflash_init(MBOOT_SPIFLASH2_SPIFLASH); + #endif + + dfu_init(); + + pyb_usbdd_init(&pyb_usbdd, MICROPY_HW_USB_MAIN_DEV); + pyb_usbdd_start(&pyb_usbdd); + + #if defined(MBOOT_I2C_SCL) + initial_r0 &= 0x7f; + if (initial_r0 == 0) { + initial_r0 = 0x23; // Default I2C address + } + i2c_init(initial_r0); + #endif + + led_state(LED0, 0); + led_state(LED1, 0); + led_state(LED2, 0); + + #if USE_USB_POLLING + uint32_t ss = systick_ms; + int ss2 = -1; + #endif + for (;;) { + #if USE_USB_POLLING + #if defined(MICROPY_HW_USB_FS) + if (pcd_fs_handle.Instance->GINTSTS & pcd_fs_handle.Instance->GINTMSK) { + HAL_PCD_IRQHandler(&pcd_fs_handle); + } + #endif + #if defined(MICROPY_HW_USB_HS) + if (pcd_hs_handle.Instance->GINTSTS & pcd_hs_handle.Instance->GINTMSK) { + HAL_PCD_IRQHandler(&pcd_hs_handle); + } + #endif + if (!pyb_usbdd.tx_pending) { + dfu_process(); + } + #endif + + #if USE_USB_POLLING + //__WFI(); // slows it down way too much; might work with 10x faster systick + if (systick_ms - ss > 50) { + ss += 50; + ss2 = (ss2 + 1) % 20; + switch (ss2) { + case 0: led_state(LED0, 1); break; + case 1: led_state(LED0, 0); break; + } + } + #else + led_state(LED0, 1); + mp_hal_delay_ms(50); + led_state(LED0, 0); + mp_hal_delay_ms(950); + #endif + } +} + +void NMI_Handler(void) { +} + +void MemManage_Handler(void) { + while (1) { + __fatal_error("MemManage"); + } +} + +void BusFault_Handler(void) { + while (1) { + __fatal_error("BusFault"); + } +} + +void UsageFault_Handler(void) { + while (1) { + __fatal_error("UsageFault"); + } +} + +void SVC_Handler(void) { +} + +void DebugMon_Handler(void) { +} + +void PendSV_Handler(void) { +} + +void SysTick_Handler(void) { + systick_ms += 1; + + // Read the systick control regster. This has the side effect of clearing + // the COUNTFLAG bit, which makes the logic in mp_hal_ticks_us + // work properly. + SysTick->CTRL; +} + +#if defined(MBOOT_I2C_SCL) +void I2Cx_EV_IRQHandler(void) { + i2c_slave_ev_irq_handler(MBOOT_I2Cx); +} +#endif + +#if !USE_USB_POLLING +#if defined(MICROPY_HW_USB_FS) +void OTG_FS_IRQHandler(void) { + HAL_PCD_IRQHandler(&pcd_fs_handle); +} +#endif +#if defined(MICROPY_HW_USB_HS) +void OTG_HS_IRQHandler(void) { + HAL_PCD_IRQHandler(&pcd_hs_handle); +} +#endif +#endif diff --git a/ports/stm32/mboot/mboot.py b/ports/stm32/mboot/mboot.py new file mode 100644 index 0000000000..39ae0f6f2d --- /dev/null +++ b/ports/stm32/mboot/mboot.py @@ -0,0 +1,177 @@ +# Driver for Mboot, the MicroPython boot loader +# MIT license; Copyright (c) 2018 Damien P. George + +import struct, time, os, hashlib + + +I2C_CMD_ECHO = 1 +I2C_CMD_GETID = 2 +I2C_CMD_GETCAPS = 3 +I2C_CMD_RESET = 4 +I2C_CMD_CONFIG = 5 +I2C_CMD_GETLAYOUT = 6 +I2C_CMD_MASSERASE = 7 +I2C_CMD_PAGEERASE = 8 +I2C_CMD_SETRDADDR = 9 +I2C_CMD_SETWRADDR = 10 +I2C_CMD_READ = 11 +I2C_CMD_WRITE = 12 +I2C_CMD_COPY = 13 +I2C_CMD_CALCHASH = 14 +I2C_CMD_MARKVALID = 15 + + +class Bootloader: + def __init__(self, i2c, addr): + self.i2c = i2c + self.addr = addr + self.buf1 = bytearray(1) + try: + self.i2c.writeto(addr, b'') + except OSError: + raise Exception('no I2C mboot device found') + + def wait_response(self): + start = time.ticks_ms() + while 1: + try: + self.i2c.readfrom_into(self.addr, self.buf1) + n = self.buf1[0] + break + except OSError as er: + time.sleep_us(500) + if time.ticks_diff(time.ticks_ms(), start) > 5000: + raise Exception('timeout') + if n >= 129: + raise Exception(n) + if n == 0: + return b'' + else: + return self.i2c.readfrom(self.addr, n) + + def wait_empty_response(self): + ret = self.wait_response() + if ret: + raise Exception('expected empty response got %r' % ret) + else: + return None + + def echo(self, data): + self.i2c.writeto(self.addr, struct.pack(' + +#define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) + +#define MP_HAL_PIN_MODE_INPUT (0) +#define MP_HAL_PIN_MODE_OUTPUT (1) +#define MP_HAL_PIN_MODE_ALT (2) +#define MP_HAL_PIN_MODE_ANALOG (3) +#define MP_HAL_PIN_MODE_OPEN_DRAIN (5) +#define MP_HAL_PIN_MODE_ALT_OPEN_DRAIN (6) +#define MP_HAL_PIN_PULL_NONE (GPIO_NOPULL) +#define MP_HAL_PIN_PULL_UP (GPIO_PULLUP) +#define MP_HAL_PIN_PULL_DOWN (GPIO_PULLDOWN) + +#define mp_hal_pin_obj_t uint32_t +#define mp_hal_pin_input(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_output(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 0) +#define mp_hal_pin_low(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 0x10000 << ((p) & 0xf)) +#define mp_hal_pin_high(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 1 << ((p) & 0xf)) +#define mp_hal_pin_od_low(p) mp_hal_pin_low(p) +#define mp_hal_pin_od_high(p) mp_hal_pin_high(p) +#define mp_hal_pin_read(p) ((((GPIO_TypeDef*)((p) & ~0xf))->IDR >> ((p) & 0xf)) & 1) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) + +void mp_hal_pin_config(uint32_t port_pin, uint32_t mode, uint32_t pull, uint32_t alt); +void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed); + +#define pin_A0 (GPIOA_BASE | 0) +#define pin_A1 (GPIOA_BASE | 1) +#define pin_A2 (GPIOA_BASE | 2) +#define pin_A3 (GPIOA_BASE | 3) +#define pin_A4 (GPIOA_BASE | 4) +#define pin_A5 (GPIOA_BASE | 5) +#define pin_A6 (GPIOA_BASE | 6) +#define pin_A7 (GPIOA_BASE | 7) +#define pin_A8 (GPIOA_BASE | 8) +#define pin_A9 (GPIOA_BASE | 9) +#define pin_A10 (GPIOA_BASE | 10) +#define pin_A11 (GPIOA_BASE | 11) +#define pin_A12 (GPIOA_BASE | 12) +#define pin_A13 (GPIOA_BASE | 13) +#define pin_A14 (GPIOA_BASE | 14) +#define pin_A15 (GPIOA_BASE | 15) + +#define pin_B0 (GPIOB_BASE | 0) +#define pin_B1 (GPIOB_BASE | 1) +#define pin_B2 (GPIOB_BASE | 2) +#define pin_B3 (GPIOB_BASE | 3) +#define pin_B4 (GPIOB_BASE | 4) +#define pin_B5 (GPIOB_BASE | 5) +#define pin_B6 (GPIOB_BASE | 6) +#define pin_B7 (GPIOB_BASE | 7) +#define pin_B8 (GPIOB_BASE | 8) +#define pin_B9 (GPIOB_BASE | 9) +#define pin_B10 (GPIOB_BASE | 10) +#define pin_B11 (GPIOB_BASE | 11) +#define pin_B12 (GPIOB_BASE | 12) +#define pin_B13 (GPIOB_BASE | 13) +#define pin_B14 (GPIOB_BASE | 14) +#define pin_B15 (GPIOB_BASE | 15) + +#define pin_C0 (GPIOC_BASE | 0) +#define pin_C1 (GPIOC_BASE | 1) +#define pin_C2 (GPIOC_BASE | 2) +#define pin_C3 (GPIOC_BASE | 3) +#define pin_C4 (GPIOC_BASE | 4) +#define pin_C5 (GPIOC_BASE | 5) +#define pin_C6 (GPIOC_BASE | 6) +#define pin_C7 (GPIOC_BASE | 7) +#define pin_C8 (GPIOC_BASE | 8) +#define pin_C9 (GPIOC_BASE | 9) +#define pin_C10 (GPIOC_BASE | 10) +#define pin_C11 (GPIOC_BASE | 11) +#define pin_C12 (GPIOC_BASE | 12) +#define pin_C13 (GPIOC_BASE | 13) +#define pin_C14 (GPIOC_BASE | 14) +#define pin_C15 (GPIOC_BASE | 15) + +#define pin_D0 (GPIOD_BASE | 0) +#define pin_D1 (GPIOD_BASE | 1) +#define pin_D2 (GPIOD_BASE | 2) +#define pin_D3 (GPIOD_BASE | 3) +#define pin_D4 (GPIOD_BASE | 4) +#define pin_D5 (GPIOD_BASE | 5) +#define pin_D6 (GPIOD_BASE | 6) +#define pin_D7 (GPIOD_BASE | 7) +#define pin_D8 (GPIOD_BASE | 8) +#define pin_D9 (GPIOD_BASE | 9) +#define pin_D10 (GPIOD_BASE | 10) +#define pin_D11 (GPIOD_BASE | 11) +#define pin_D12 (GPIOD_BASE | 12) +#define pin_D13 (GPIOD_BASE | 13) +#define pin_D14 (GPIOD_BASE | 14) +#define pin_D15 (GPIOD_BASE | 15) + +#define pin_E0 (GPIOE_BASE | 0) +#define pin_E1 (GPIOE_BASE | 1) +#define pin_E2 (GPIOE_BASE | 2) +#define pin_E3 (GPIOE_BASE | 3) +#define pin_E4 (GPIOE_BASE | 4) +#define pin_E5 (GPIOE_BASE | 5) +#define pin_E6 (GPIOE_BASE | 6) +#define pin_E7 (GPIOE_BASE | 7) +#define pin_E8 (GPIOE_BASE | 8) +#define pin_E9 (GPIOE_BASE | 9) +#define pin_E10 (GPIOE_BASE | 10) +#define pin_E11 (GPIOE_BASE | 11) +#define pin_E12 (GPIOE_BASE | 12) +#define pin_E13 (GPIOE_BASE | 13) +#define pin_E14 (GPIOE_BASE | 14) +#define pin_E15 (GPIOE_BASE | 15) + +#define pin_F0 (GPIOF_BASE | 0) +#define pin_F1 (GPIOF_BASE | 1) +#define pin_F2 (GPIOF_BASE | 2) +#define pin_F3 (GPIOF_BASE | 3) +#define pin_F4 (GPIOF_BASE | 4) +#define pin_F5 (GPIOF_BASE | 5) +#define pin_F6 (GPIOF_BASE | 6) +#define pin_F7 (GPIOF_BASE | 7) +#define pin_F8 (GPIOF_BASE | 8) +#define pin_F9 (GPIOF_BASE | 9) +#define pin_F10 (GPIOF_BASE | 10) +#define pin_F11 (GPIOF_BASE | 11) +#define pin_F12 (GPIOF_BASE | 12) +#define pin_F13 (GPIOF_BASE | 13) +#define pin_F14 (GPIOF_BASE | 14) +#define pin_F15 (GPIOF_BASE | 15) diff --git a/ports/stm32/mboot/stm32_generic.ld b/ports/stm32/mboot/stm32_generic.ld new file mode 100644 index 0000000000..8585c68734 --- /dev/null +++ b/ports/stm32/mboot/stm32_generic.ld @@ -0,0 +1,77 @@ +/* + GNU linker script for generic STM32xxx MCU +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 (can be 32K) */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; + +/* Define tho top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +ENTRY(Reset_Handler) + +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH_BL + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + } >FLASH_BL + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data section */ + .data : + { + . = ALIGN(4); + _sdata = .; + *(.data*) + + . = ALIGN(4); + _edata = .; + } >RAM AT> FLASH_BL + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 8c59758fa3..158f5f2b34 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -54,11 +54,29 @@ #include "wdt.h" #include "genhdr/pllfreqtable.h" -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) // L4 does not have a POR, so use BOR instead #define RCC_CSR_PORRSTF RCC_CSR_BORRSTF #endif +#if defined(STM32H7) +#define RCC_SR RSR +#define RCC_SR_IWDGRSTF RCC_RSR_IWDG1RSTF +#define RCC_SR_WWDGRSTF RCC_RSR_WWDG1RSTF +#define RCC_SR_PORRSTF RCC_RSR_PORRSTF +#define RCC_SR_BORRSTF RCC_RSR_BORRSTF +#define RCC_SR_PINRSTF RCC_RSR_PINRSTF +#define RCC_SR_RMVF RCC_RSR_RMVF +#else +#define RCC_SR CSR +#define RCC_SR_IWDGRSTF RCC_CSR_IWDGRSTF +#define RCC_SR_WWDGRSTF RCC_CSR_WWDGRSTF +#define RCC_SR_PORRSTF RCC_CSR_PORRSTF +#define RCC_SR_BORRSTF RCC_CSR_BORRSTF +#define RCC_SR_PINRSTF RCC_CSR_PINRSTF +#define RCC_SR_RMVF RCC_CSR_RMVF +#endif + #define PYB_RESET_SOFT (0) #define PYB_RESET_POWER_ON (1) #define PYB_RESET_HARD (2) @@ -68,27 +86,37 @@ STATIC uint32_t reset_cause; void machine_init(void) { - #if defined(MCU_SERIES_F4) + #if defined(STM32F4) if (PWR->CSR & PWR_CSR_SBF) { // came out of standby reset_cause = PYB_RESET_DEEPSLEEP; PWR->CR |= PWR_CR_CSBF; } else - #elif defined(MCU_SERIES_F7) + #elif defined(STM32F7) if (PWR->CSR1 & PWR_CSR1_SBF) { // came out of standby reset_cause = PYB_RESET_DEEPSLEEP; PWR->CR1 |= PWR_CR1_CSBF; } else + #elif defined(STM32H7) + if (PWR->CPUCR & PWR_CPUCR_SBF || PWR->CPUCR & PWR_CPUCR_STOPF) { + // came out of standby or stop mode + reset_cause = PYB_RESET_DEEPSLEEP; + PWR->CPUCR |= PWR_CPUCR_CSSF; + } else #endif { // get reset cause from RCC flags - uint32_t state = RCC->CSR; - if (state & RCC_CSR_IWDGRSTF || state & RCC_CSR_WWDGRSTF) { + uint32_t state = RCC->RCC_SR; + if (state & RCC_SR_IWDGRSTF || state & RCC_SR_WWDGRSTF) { reset_cause = PYB_RESET_WDT; - } else if (state & RCC_CSR_PORRSTF || state & RCC_CSR_BORRSTF) { + } else if (state & RCC_SR_PORRSTF + #if !defined(STM32F0) + || state & RCC_SR_BORRSTF + #endif + ) { reset_cause = PYB_RESET_POWER_ON; - } else if (state & RCC_CSR_PINRSTF) { + } else if (state & RCC_SR_PINRSTF) { reset_cause = PYB_RESET_HARD; } else { // default is soft reset @@ -96,7 +124,12 @@ void machine_init(void) { } } // clear RCC reset flags - RCC->CSR |= RCC_CSR_RMVF; + RCC->RCC_SR |= RCC_SR_RMVF; +} + +void machine_deinit(void) { + // we are doing a soft-reset so change the reset_cause + reset_cause = PYB_RESET_SOFT; } // machine.info([dump_alloc_table]) @@ -111,11 +144,18 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { // get and print clock speeds // SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz { - printf("S=%lu\nH=%lu\nP1=%lu\nP2=%lu\n", - HAL_RCC_GetSysClockFreq(), - HAL_RCC_GetHCLKFreq(), - HAL_RCC_GetPCLK1Freq(), - HAL_RCC_GetPCLK2Freq()); + #if defined(STM32F0) + printf("S=%u\nH=%u\nP1=%u\n", + (unsigned int)HAL_RCC_GetSysClockFreq(), + (unsigned int)HAL_RCC_GetHCLKFreq(), + (unsigned int)HAL_RCC_GetPCLK1Freq()); + #else + printf("S=%u\nH=%u\nP1=%u\nP2=%u\n", + (unsigned int)HAL_RCC_GetSysClockFreq(), + (unsigned int)HAL_RCC_GetHCLKFreq(), + (unsigned int)HAL_RCC_GetPCLK1Freq(), + (unsigned int)HAL_RCC_GetPCLK2Freq()); + #endif } // to print info about memory @@ -152,6 +192,7 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { // free space on flash { + #if MICROPY_VFS_FAT for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { if (strncmp("/flash", vfs->str, vfs->len) == 0) { // assumes that it's a FatFs filesystem @@ -162,6 +203,7 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) { break; } } + #endif } #if MICROPY_PY_THREAD @@ -199,8 +241,12 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); // Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t machine_bootloader(void) { + #if MICROPY_HW_ENABLE_USB pyb_usb_dev_deinit(); + #endif + #if MICROPY_HW_ENABLE_STORAGE storage_flush(); + #endif HAL_RCC_DeInit(); HAL_DeInit(); @@ -210,7 +256,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { HAL_MPU_Disable(); #endif -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) || defined(STM32H7) // arm-none-eabi-gcc 4.9.0 does not correctly inline this // MSP function, so we write it out explicitly here. //__set_MSP(*((uint32_t*) 0x1FF00000)); @@ -218,7 +264,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { ((void (*)(void)) *((uint32_t*) 0x1FF00004))(); #else - __HAL_REMAPMEMORY_SYSTEMFLASH(); + __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); // arm-none-eabi-gcc 4.9.0 does not correctly inline this // MSP function, so we write it out explicitly here. @@ -232,6 +278,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader); +#if !(defined(STM32F0) || defined(STM32L4)) // get or set the MCU frequencies STATIC mp_uint_t machine_freq_calc_ahb_div(mp_uint_t wanted_div) { if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; } @@ -251,23 +298,28 @@ STATIC mp_uint_t machine_freq_calc_apb_div(mp_uint_t wanted_div) { else if (wanted_div <= 8) { return RCC_HCLK_DIV8; } else { return RCC_SYSCLK_DIV16; } } +#endif + STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { // get - mp_obj_t tuple[4] = { + mp_obj_t tuple[] = { mp_obj_new_int(HAL_RCC_GetSysClockFreq()), mp_obj_new_int(HAL_RCC_GetHCLKFreq()), mp_obj_new_int(HAL_RCC_GetPCLK1Freq()), + #if !defined(STM32F0) mp_obj_new_int(HAL_RCC_GetPCLK2Freq()), + #endif }; - return mp_obj_new_tuple(4, tuple); + return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); } else { // set - mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000; - #if defined(MCU_SERIES_L4) + #if defined(STM32F0) || defined(STM32L4) mp_raise_NotImplementedError("machine.freq set not supported yet"); - #endif + #else + + mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000; // default PLL parameters that give 48MHz on PLL48CK uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7; @@ -346,7 +398,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { // even if we don't use the PLL for the system clock, we still need it for USB, RNG and SDIO RCC_OscInitTypeDef RCC_OscInitStruct; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.HSEState = MICROPY_HW_CLK_HSE_STATE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = m; @@ -359,33 +411,50 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { // set PLL as system clock source if wanted if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) { - #if defined(MCU_SERIES_F7) + uint32_t flash_latency; + #if defined(STM32F7) // if possible, scale down the internal voltage regulator to save power + // the flash_latency values assume a supply voltage between 2.7V and 3.6V uint32_t volt_scale; - if (wanted_sysclk <= 151000000) { + if (wanted_sysclk <= 90000000) { volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3; + flash_latency = FLASH_LATENCY_2; + } else if (wanted_sysclk <= 120000000) { + volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3; + flash_latency = FLASH_LATENCY_3; + } else if (wanted_sysclk <= 144000000) { + volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3; + flash_latency = FLASH_LATENCY_4; } else if (wanted_sysclk <= 180000000) { volt_scale = PWR_REGULATOR_VOLTAGE_SCALE2; + flash_latency = FLASH_LATENCY_5; + } else if (wanted_sysclk <= 210000000) { + volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1; + flash_latency = FLASH_LATENCY_6; } else { volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1; + flash_latency = FLASH_LATENCY_7; } if (HAL_PWREx_ControlVoltageScaling(volt_scale) != HAL_OK) { goto fail; } #endif + #if !defined(STM32F7) #if !defined(MICROPY_HW_FLASH_LATENCY) #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5 #endif + flash_latency = MICROPY_HW_FLASH_LATENCY; + #endif RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, MICROPY_HW_FLASH_LATENCY) != HAL_OK) { + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, flash_latency) != HAL_OK) { goto fail; } } #if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) #define FREQ_BKP BKP31R #else #define FREQ_BKP BKP19R @@ -406,12 +475,14 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { fail:; void NORETURN __fatal_error(const char *msg); __fatal_error("can't change freq"); + + #endif } } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 4, machine_freq); STATIC mp_obj_t machine_sleep(void) { - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) // Enter Stop 1 mode __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); @@ -440,10 +511,12 @@ STATIC mp_obj_t machine_sleep(void) { #else + #if !defined(STM32F0) // takes longer to wake but reduces stop current HAL_PWREx_EnableFlashPowerDown(); + #endif - # if defined(MCU_SERIES_F7) + # if defined(STM32F7) HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI); # else HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); @@ -452,7 +525,7 @@ STATIC mp_obj_t machine_sleep(void) { // reconfigure the system clock after waking up // enable HSE - __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE); while (!__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY)) { } @@ -463,7 +536,11 @@ STATIC mp_obj_t machine_sleep(void) { // select PLL as system clock source MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK); + #if defined(STM32H7) + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) { + #else while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) { + #endif } #endif @@ -475,7 +552,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); STATIC mp_obj_t machine_deepsleep(void) { rtc_init_finalise(); -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) printf("machine.deepsleep not supported yet\n"); #else // We need to clear the PWR wake-up-flag before entering standby, since @@ -486,22 +563,30 @@ STATIC mp_obj_t machine_deepsleep(void) { // Note: we only support RTC ALRA, ALRB, WUT and TS. // TODO support TAMP and WKUP (PA0 external pin). - uint32_t irq_bits = RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE; + #if defined(STM32F0) + #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_WUTIE | RTC_CR_TSIE) + #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TSF) + #else + #define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE) + #define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF) + #endif // save RTC interrupts - uint32_t save_irq_bits = RTC->CR & irq_bits; + uint32_t save_irq_bits = RTC->CR & CR_BITS; // disable RTC interrupts - RTC->CR &= ~irq_bits; + RTC->CR &= ~CR_BITS; // clear RTC wake-up flags - RTC->ISR &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF); + RTC->ISR &= ~ISR_BITS; - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) // disable wake-up flags PWR->CSR2 &= ~(PWR_CSR2_EWUP6 | PWR_CSR2_EWUP5 | PWR_CSR2_EWUP4 | PWR_CSR2_EWUP3 | PWR_CSR2_EWUP2 | PWR_CSR2_EWUP1); // clear global wake-up flag PWR->CR2 |= PWR_CR2_CWUPF6 | PWR_CR2_CWUPF5 | PWR_CR2_CWUPF4 | PWR_CR2_CWUPF3 | PWR_CR2_CWUPF2 | PWR_CR2_CWUPF1; + #elif defined(STM32H7) + // TODO #else // clear global wake-up flag PWR->CR |= PWR_CR_CWUF; @@ -558,7 +643,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, #endif +#if MICROPY_PY_MACHINE_I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, +#endif { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&pyb_wdt_type) }, diff --git a/ports/stm32/modmachine.h b/ports/stm32/modmachine.h index 77668695fc..88fe236921 100644 --- a/ports/stm32/modmachine.h +++ b/ports/stm32/modmachine.h @@ -23,12 +23,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_MODMACHINE_H -#define MICROPY_INCLUDED_STMHAL_MODMACHINE_H +#ifndef MICROPY_INCLUDED_STM32_MODMACHINE_H +#define MICROPY_INCLUDED_STM32_MODMACHINE_H #include "py/obj.h" void machine_init(void); +void machine_deinit(void); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj); @@ -38,4 +39,4 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_sleep_obj); MP_DECLARE_CONST_FUN_OBJ_0(machine_deepsleep_obj); -#endif // MICROPY_INCLUDED_STMHAL_MODMACHINE_H +#endif // MICROPY_INCLUDED_STM32_MODMACHINE_H diff --git a/ports/stm32/modnetwork.c b/ports/stm32/modnetwork.c index 6421745325..cf7ecbf3c0 100644 --- a/ports/stm32/modnetwork.c +++ b/ports/stm32/modnetwork.c @@ -30,10 +30,37 @@ #include "py/objlist.h" #include "py/runtime.h" +#include "py/mphal.h" +#include "lib/netutils/netutils.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" + +u32_t sys_now(void) { + return mp_hal_ticks_ms(); +} + +void pyb_lwip_poll(void) { + // Poll all the NICs for incoming data + for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { + if (netif->flags & NETIF_FLAG_LINK_UP) { + mod_network_nic_type_t *nic = netif->state; + nic->poll_callback(nic, netif); + } + } + // Run the lwIP internal updates + sys_check_timeouts(); +} + +#endif + /// \module network - network configuration /// /// This module provides network drivers and routing configuration. @@ -42,6 +69,9 @@ void mod_network_init(void) { mp_obj_list_init(&MP_STATE_PORT(mod_network_nic_list), 0); } +void mod_network_deinit(void) { +} + void mod_network_register_nic(mp_obj_t nic) { for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) { if (MP_STATE_PORT(mod_network_nic_list).items[i] == nic) { @@ -90,4 +120,58 @@ const mp_obj_module_t mp_module_network = { .globals = (mp_obj_dict_t*)&mp_module_network_globals, }; +/*******************************************************************************/ +// Implementations of network methods that can be used by any interface + +#if MICROPY_PY_LWIP + +mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // Get IP addresses + const ip_addr_t *dns = dns_getserver(0); + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr((uint8_t*)&netif->ip_addr, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&netif->netmask, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&netif->gw, NETUTILS_BIG), + netutils_format_ipv4_addr((uint8_t*)&dns, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else if (args[0] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) { + // Start the DHCP client + if (dhcp_supplied_address(netif)) { + dhcp_renew(netif); + } else { + dhcp_stop(netif); + dhcp_start(netif); + } + + // Wait for DHCP to get IP address + uint32_t start = mp_hal_ticks_ms(); + while (!dhcp_supplied_address(netif)) { + if (mp_hal_ticks_ms() - start > 10000) { + mp_raise_msg(&mp_type_OSError, "timeout waiting for DHCP to get IP address"); + } + mp_hal_delay_ms(100); + } + + return mp_const_none; + } else { + // Release and stop any existing DHCP + dhcp_release(netif); + dhcp_stop(netif); + // Set static IP addresses + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[0], 4, &items); + netutils_parse_ipv4_addr(items[0], (uint8_t*)&netif->ip_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[1], (uint8_t*)&netif->netmask, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[2], (uint8_t*)&netif->gw, NETUTILS_BIG); + ip_addr_t dns; + netutils_parse_ipv4_addr(items[3], (uint8_t*)&dns, NETUTILS_BIG); + dns_setserver(0, &dns); + return mp_const_none; + } +} + +#endif + #endif // MICROPY_PY_NETWORK diff --git a/ports/stm32/modnetwork.h b/ports/stm32/modnetwork.h index ecda94da41..f45e00fbc2 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_MODNETWORK_H -#define MICROPY_INCLUDED_STMHAL_MODNETWORK_H +#ifndef MICROPY_INCLUDED_STM32_MODNETWORK_H +#define MICROPY_INCLUDED_STM32_MODNETWORK_H #define MOD_NETWORK_IPADDR_BUF_SIZE (4) @@ -35,6 +35,21 @@ #define MOD_NETWORK_SOCK_DGRAM (2) #define MOD_NETWORK_SOCK_RAW (3) +#if MICROPY_PY_LWIP + +struct netif; + +typedef struct _mod_network_nic_type_t { + mp_obj_base_t base; + void (*poll_callback)(void *data, struct netif *netif); +} mod_network_nic_type_t; + +extern const mp_obj_type_t mod_network_nic_type_wiznet5k; + +mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args); + +#else + struct _mod_network_socket_obj_t; typedef struct _mod_network_nic_type_t { @@ -76,8 +91,11 @@ typedef struct _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 + 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_STMHAL_MODNETWORK_H +#endif // MICROPY_INCLUDED_STM32_MODNETWORK_H diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c index 8cc0a613d1..8723994f45 100644 --- a/ports/stm32/modnwcc3k.c +++ b/ports/stm32/modnwcc3k.c @@ -39,7 +39,6 @@ #include "lib/netutils/netutils.h" #include "modnetwork.h" #include "pin.h" -#include "genhdr/pins.h" #include "spi.h" #include "hci.h" @@ -433,7 +432,7 @@ STATIC mp_obj_t cc3k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n // set the pins to use SpiInit( - spi_get_handle(args[0]), + spi_from_mp_obj(args[0])->spi, pin_find(args[1]), pin_find(args[2]), pin_find(args[3]) @@ -531,8 +530,8 @@ STATIC mp_obj_t cc3k_ifconfig(mp_obj_t self_in) { netutils_format_ipv4_addr(ipconfig.aucDefaultGateway, NETUTILS_LITTLE), netutils_format_ipv4_addr(ipconfig.aucDNSServer, NETUTILS_LITTLE), netutils_format_ipv4_addr(ipconfig.aucDHCPServer, NETUTILS_LITTLE), - mp_obj_new_str(mac_vstr.buf, mac_vstr.len, false), - mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID), false), + mp_obj_new_str(mac_vstr.buf, mac_vstr.len), + mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID)), }; return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); } diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c index 763137c703..bf4b72ff21 100644 --- a/ports/stm32/modnwwiznet5k.c +++ b/ports/stm32/modnwwiznet5k.c @@ -36,9 +36,10 @@ #include "lib/netutils/netutils.h" #include "modnetwork.h" #include "pin.h" -#include "genhdr/pins.h" #include "spi.h" +#if MICROPY_PY_WIZNET5K && !MICROPY_PY_LWIP + #include "ethernet/wizchip_conf.h" #include "ethernet/socket.h" #include "internet/dns/dns.h" @@ -48,7 +49,7 @@ typedef struct _wiznet5k_obj_t { mp_obj_base_t base; mp_uint_t cris_state; - SPI_HandleTypeDef *spi; + const spi_t *spi; const pin_obj_t *cs; const pin_obj_t *rst; uint8_t socket_used; @@ -73,12 +74,12 @@ STATIC void wiz_cs_deselect(void) { } STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) { - HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi, buf, len, 5000); + HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi->spi, buf, len, 5000); (void)status; } STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) { - HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi, (uint8_t*)buf, len, 5000); + HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi->spi, (uint8_t*)buf, len, 5000); (void)status; } @@ -345,23 +346,24 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size // init the wiznet5k object wiznet5k_obj.base.type = (mp_obj_type_t*)&mod_network_nic_type_wiznet5k; wiznet5k_obj.cris_state = 0; - wiznet5k_obj.spi = spi_get_handle(args[0]); + wiznet5k_obj.spi = spi_from_mp_obj(args[0]); wiznet5k_obj.cs = pin_find(args[1]); wiznet5k_obj.rst = pin_find(args[2]); wiznet5k_obj.socket_used = 0; /*!< SPI configuration */ - wiznet5k_obj.spi->Init.Mode = SPI_MODE_MASTER; - wiznet5k_obj.spi->Init.Direction = SPI_DIRECTION_2LINES; - wiznet5k_obj.spi->Init.DataSize = SPI_DATASIZE_8BIT; - wiznet5k_obj.spi->Init.CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle - wiznet5k_obj.spi->Init.CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle - wiznet5k_obj.spi->Init.NSS = SPI_NSS_SOFT; - wiznet5k_obj.spi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz - wiznet5k_obj.spi->Init.FirstBit = SPI_FIRSTBIT_MSB; - wiznet5k_obj.spi->Init.TIMode = SPI_TIMODE_DISABLED; - wiznet5k_obj.spi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; - wiznet5k_obj.spi->Init.CRCPolynomial = 7; // unused + SPI_InitTypeDef *init = &wiznet5k_obj.spi->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle + init->CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; // unused spi_init(wiznet5k_obj.spi, false); mp_hal_pin_output(wiznet5k_obj.cs); @@ -499,3 +501,5 @@ const mod_network_nic_type_t mod_network_nic_type_wiznet5k = { .settimeout = wiznet5k_socket_settimeout, .ioctl = wiznet5k_socket_ioctl, }; + +#endif // MICROPY_PY_WIZNET5K && !MICROPY_PY_LWIP diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 81cbdcc191..5afbbc4842 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -28,18 +28,12 @@ #include #include "py/runtime.h" -#include "py/gc.h" -#include "py/builtin.h" #include "py/mphal.h" #include "lib/utils/pyexec.h" -#include "lib/oofatfs/ff.h" -#include "lib/oofatfs/diskio.h" -#include "gccollect.h" +#include "drivers/dht/dht.h" #include "stm32_it.h" #include "irq.h" -#include "systick.h" #include "led.h" -#include "pin.h" #include "timer.h" #include "extint.h" #include "usrsw.h" @@ -68,16 +62,10 @@ STATIC mp_obj_t pyb_fault_debug(mp_obj_t value) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_fault_debug_obj, pyb_fault_debug); -/// \function elapsed_millis(start) -/// Returns the number of milliseconds which have elapsed since `start`. -/// -/// This function takes care of counter wrap, and always returns a positive -/// number. This means it can be used to measure periods upto about 12.4 days. -/// -/// Example: -/// start = pyb.millis() -/// while pyb.elapsed_millis(start) < 1000: -/// # Perform some operation +#if MICROPY_PY_PYB_LEGACY + +// Returns the number of milliseconds which have elapsed since `start`. +// This function takes care of counter wrap and always returns a positive number. STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) { uint32_t startMillis = mp_obj_get_int(start); uint32_t currMillis = mp_hal_ticks_ms(); @@ -85,16 +73,8 @@ STATIC mp_obj_t pyb_elapsed_millis(mp_obj_t start) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_millis_obj, pyb_elapsed_millis); -/// \function elapsed_micros(start) -/// Returns the number of microseconds which have elapsed since `start`. -/// -/// This function takes care of counter wrap, and always returns a positive -/// number. This means it can be used to measure periods upto about 17.8 minutes. -/// -/// Example: -/// start = pyb.micros() -/// while pyb.elapsed_micros(start) < 1000: -/// # Perform some operation +// Returns the number of microseconds which have elapsed since `start`. +// This function takes care of counter wrap and always returns a positive number. STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) { uint32_t startMicros = mp_obj_get_int(start); uint32_t currMicros = mp_hal_ticks_us(); @@ -102,6 +82,8 @@ STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros); +#endif + MP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c // Get or set the UART object that the REPL is repeated on. @@ -115,9 +97,13 @@ STATIC mp_obj_t pyb_repl_uart(size_t n_args, const mp_obj_t *args) { } } else { if (args[0] == mp_const_none) { - MP_STATE_PORT(pyb_stdio_uart) = NULL; + if (MP_STATE_PORT(pyb_stdio_uart) != NULL) { + uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), false); + MP_STATE_PORT(pyb_stdio_uart) = NULL; + } } else if (mp_obj_get_type(args[0]) == &pyb_uart_type) { MP_STATE_PORT(pyb_stdio_uart) = args[0]; + uart_attach_to_repl(MP_STATE_PORT(pyb_stdio_uart), true); } else { mp_raise_ValueError("need a UART object"); } @@ -131,11 +117,13 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_fault_debug), MP_ROM_PTR(&pyb_fault_debug_obj) }, + #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) }, { MP_ROM_QSTR(MP_QSTR_hard_reset), MP_ROM_PTR(&machine_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) }, { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_repl_info), MP_ROM_PTR(&pyb_set_repl_info_obj) }, { MP_ROM_QSTR(MP_QSTR_wfi), MP_ROM_PTR(&pyb_wfi_obj) }, @@ -145,20 +133,27 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_irq_stats), MP_ROM_PTR(&pyb_irq_stats_obj) }, #endif + #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_sleep_obj) }, { MP_ROM_QSTR(MP_QSTR_standby), MP_ROM_PTR(&machine_deepsleep_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) }, { MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&pyb_repl_uart_obj) }, + #if MICROPY_HW_ENABLE_USB { MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) }, { MP_ROM_QSTR(MP_QSTR_hid_mouse), MP_ROM_PTR(&pyb_usb_hid_mouse_obj) }, { MP_ROM_QSTR(MP_QSTR_hid_keyboard), MP_ROM_PTR(&pyb_usb_hid_keyboard_obj) }, { MP_ROM_QSTR(MP_QSTR_USB_VCP), MP_ROM_PTR(&pyb_usb_vcp_type) }, { MP_ROM_QSTR(MP_QSTR_USB_HID), MP_ROM_PTR(&pyb_usb_hid_type) }, + #if MICROPY_PY_PYB_LEGACY // these 2 are deprecated; use USB_VCP.isconnected and USB_HID.send instead { MP_ROM_QSTR(MP_QSTR_have_cdc), MP_ROM_PTR(&pyb_have_cdc_obj) }, { MP_ROM_QSTR(MP_QSTR_hid), MP_ROM_PTR(&pyb_hid_send_report_obj) }, + #endif + #endif + #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_elapsed_millis), MP_ROM_PTR(&pyb_elapsed_millis_obj) }, { MP_ROM_QSTR(MP_QSTR_micros), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, @@ -167,6 +162,10 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_udelay), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) }, { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + #endif + + // This function is not intended to be public and may be moved elsewhere + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) }, @@ -196,22 +195,28 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #endif #if MICROPY_HW_HAS_SDCARD + #if MICROPY_PY_PYB_LEGACY { MP_ROM_QSTR(MP_QSTR_SD), MP_ROM_PTR(&pyb_sdcard_obj) }, // now obsolete + #endif { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&pyb_sdcard_type) }, #endif #if defined(MICROPY_HW_LED1) { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) }, #endif + #if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) }, + #endif { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, #if MICROPY_HW_ENABLE_CAN { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&pyb_can_type) }, #endif + #if MICROPY_HW_ENABLE_ADC { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, { MP_ROM_QSTR(MP_QSTR_ADCAll), MP_ROM_PTR(&pyb_adc_all_type) }, + #endif #if MICROPY_HW_ENABLE_DAC { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pyb_dac_type) }, diff --git a/ports/stm32/modstm.c b/ports/stm32/modstm.c index 2084c0aa0e..3fae3a57c4 100644 --- a/ports/stm32/modstm.c +++ b/ports/stm32/modstm.c @@ -30,9 +30,12 @@ #include "py/obj.h" #include "py/objint.h" #include "extmod/machine_mem.h" -#include "genhdr/modstm_mpz.h" #include "portmodules.h" +#if MICROPY_PY_STM + +#include "genhdr/modstm_mpz.h" + STATIC const mp_rom_map_elem_t stm_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_stm) }, @@ -49,3 +52,5 @@ const mp_obj_module_t stm_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&stm_module_globals, }; + +#endif // MICROPY_PY_STM diff --git a/ports/stm32/modules/dht.py b/ports/stm32/modules/dht.py new file mode 120000 index 0000000000..2aa2f5cbfe --- /dev/null +++ b/ports/stm32/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c index f6e1483d35..0dde844f30 100644 --- a/ports/stm32/moduos.c +++ b/ports/stm32/moduos.c @@ -82,10 +82,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); /// \function sync() /// Sync all filesystems. STATIC mp_obj_t os_sync(void) { + #if MICROPY_VFS_FAT for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { // this assumes that vfs->obj is fs_user_mount_t with block device functions disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL); } + #endif return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(mod_os_sync_obj, os_sync); @@ -106,6 +108,18 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); #endif +STATIC mp_obj_t uos_dupterm(size_t n_args, const mp_obj_t *args) { + mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args); + if (mp_obj_get_type(prev_obj) == &pyb_uart_type) { + uart_attach_to_repl(MP_OBJ_TO_PTR(prev_obj), false); + } + if (mp_obj_get_type(args[0]) == &pyb_uart_type) { + uart_attach_to_repl(MP_OBJ_TO_PTR(args[0]), true); + } + return prev_obj; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uos_dupterm_obj, 1, 2, uos_dupterm); + STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, @@ -133,10 +147,12 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { #endif // these are MicroPython extensions - { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&uos_dupterm_obj) }, { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, + #if MICROPY_VFS_FAT { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table); diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c index 71a237b0d9..715faa3c4b 100644 --- a/ports/stm32/modusocket.c +++ b/ports/stm32/modusocket.c @@ -30,11 +30,12 @@ #include "py/objtuple.h" #include "py/objlist.h" #include "py/runtime.h" +#include "py/stream.h" #include "py/mperrno.h" #include "lib/netutils/netutils.h" #include "modnetwork.h" -#if MICROPY_PY_USOCKET +#if MICROPY_PY_USOCKET && !MICROPY_PY_LWIP /******************************************************************************/ // socket class @@ -79,16 +80,6 @@ STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) { } } } -// method socket.close() -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mod_network_socket_obj_t *self = self_in; - if (self->nic != MP_OBJ_NULL) { - self->nic_type->close(self); - self->nic = MP_OBJ_NULL; - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); // method socket.bind(address) STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { @@ -347,8 +338,8 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, @@ -366,6 +357,13 @@ STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { mod_network_socket_obj_t *self = self_in; + if (request == MP_STREAM_CLOSE) { + if (self->nic != MP_OBJ_NULL) { + self->nic_type->close(self); + self->nic = MP_OBJ_NULL; + } + return 0; + } return self->nic_type->ioctl(self, request, arg, errcode); } @@ -467,4 +465,4 @@ const mp_obj_module_t mp_module_usocket = { .globals = (mp_obj_dict_t*)&mp_module_usocket_globals, }; -#endif // MICROPY_PY_USOCKET +#endif // MICROPY_PY_USOCKET && !MICROPY_PY_LWIP diff --git a/ports/stm32/modutime.c b/ports/stm32/modutime.c index 54045f4c5c..6b5c841151 100644 --- a/ports/stm32/modutime.c +++ b/ports/stm32/modutime.c @@ -60,8 +60,8 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { rtc_init_finalise(); RTC_DateTypeDef date; RTC_TimeTypeDef time; - HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); - HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); mp_obj_t tuple[8] = { mp_obj_new_int(2000 + date.Year), mp_obj_new_int(date.Month), @@ -123,8 +123,8 @@ STATIC mp_obj_t time_time(void) { rtc_init_finalise(); RTC_DateTypeDef date; RTC_TimeTypeDef time; - HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); - HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); return mp_obj_new_int(timeutils_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds)); } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h new file mode 100644 index 0000000000..2cc02b77cf --- /dev/null +++ b/ports/stm32/mpconfigboard_common.h @@ -0,0 +1,218 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Common settings and defaults for board configuration. +// The defaults here should be overridden in mpconfigboard.h. + +#include STM32_HAL_H + +/*****************************************************************************/ +// Feature settings with defaults + +// Whether to include the stm module, with peripheral register constants +#ifndef MICROPY_PY_STM +#define MICROPY_PY_STM (1) +#endif + +// Whether to include legacy functions and classes in the pyb module +#ifndef MICROPY_PY_PYB_LEGACY +#define MICROPY_PY_PYB_LEGACY (1) +#endif + +// Whether to enable storage on the internal flash of the MCU +#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) +#endif + +// Whether to enable the RTC, exposed as pyb.RTC +#ifndef MICROPY_HW_ENABLE_RTC +#define MICROPY_HW_ENABLE_RTC (0) +#endif + +// Whether to enable the hardware RNG peripheral, exposed as pyb.rng() +#ifndef MICROPY_HW_ENABLE_RNG +#define MICROPY_HW_ENABLE_RNG (0) +#endif + +// Whether to enable the ADC peripheral, exposed as pyb.ADC and pyb.ADCAll +#ifndef MICROPY_HW_ENABLE_ADC +#define MICROPY_HW_ENABLE_ADC (1) +#endif + +// Whether to enable the DAC peripheral, exposed as pyb.DAC +#ifndef MICROPY_HW_ENABLE_DAC +#define MICROPY_HW_ENABLE_DAC (0) +#endif + +// Whether to enable USB support +#ifndef MICROPY_HW_ENABLE_USB +#define MICROPY_HW_ENABLE_USB (0) +#endif + +// Whether to enable the PA0-PA3 servo driver, exposed as pyb.Servo +#ifndef MICROPY_HW_ENABLE_SERVO +#define MICROPY_HW_ENABLE_SERVO (0) +#endif + +// Whether to enable a USR switch, exposed as pyb.Switch +#ifndef MICROPY_HW_HAS_SWITCH +#define MICROPY_HW_HAS_SWITCH (0) +#endif + +// Whether to expose internal flash storage as pyb.Flash +#ifndef MICROPY_HW_HAS_FLASH +#define MICROPY_HW_HAS_FLASH (0) +#endif + +// Whether to enable the SD card interface, exposed as pyb.SDCard +#ifndef MICROPY_HW_HAS_SDCARD +#define MICROPY_HW_HAS_SDCARD (0) +#endif + +// Whether to enable the MMA7660 driver, exposed as pyb.Accel +#ifndef MICROPY_HW_HAS_MMA7660 +#define MICROPY_HW_HAS_MMA7660 (0) +#endif + +// Whether to enable the LCD32MK driver, exposed as pyb.LCD +#ifndef MICROPY_HW_HAS_LCD +#define MICROPY_HW_HAS_LCD (0) +#endif + +// The volume label used when creating the flash filesystem +#ifndef MICROPY_HW_FLASH_FS_LABEL +#define MICROPY_HW_FLASH_FS_LABEL "pybflash" +#endif + +/*****************************************************************************/ +// General configuration + +// Configuration for STM32F0 series +#if defined(STM32F0) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ffff7ac) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + +// Configuration for STM32F4 series +#elif defined(STM32F4) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (14) +#ifdef UART8 +#define MICROPY_HW_MAX_UART (8) +#else +#define MICROPY_HW_MAX_UART (6) +#endif + +// Configuration for STM32F7 series +#elif defined(STM32F7) + +#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff07a10) +#else +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff0f420) +#endif + +#define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + +// Configuration for STM32H7 series +#elif defined(STM32H7) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff1e800) +#define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + +// Configuration for STM32L4 series +#elif defined(STM32L4) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7590) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (6) + +#else +#error Unsupported MCU series +#endif + +// Configure HSE for bypass or oscillator +#if MICROPY_HW_CLK_USE_BYPASS +#define MICROPY_HW_CLK_HSE_STATE (RCC_HSE_BYPASS) +#else +#define MICROPY_HW_CLK_HSE_STATE (RCC_HSE_ON) +#endif + +#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +// Provide block device macros if internal flash storage is enabled +#define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl +#define MICROPY_HW_BDEV_READBLOCK flash_bdev_readblock +#define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock +#endif + +// Enable the storage sub-system if a block device is defined +#if defined(MICROPY_HW_BDEV_IOCTL) +#define MICROPY_HW_ENABLE_STORAGE (1) +#else +#define MICROPY_HW_ENABLE_STORAGE (0) +#endif + +// Enable hardware I2C if there are any peripherals defined +#if defined(MICROPY_HW_I2C1_SCL) || defined(MICROPY_HW_I2C2_SCL) \ + || defined(MICROPY_HW_I2C3_SCL) || defined(MICROPY_HW_I2C4_SCL) +#define MICROPY_HW_ENABLE_HW_I2C (1) +#else +#define MICROPY_HW_ENABLE_HW_I2C (0) +#endif + +// Enable CAN if there are any peripherals defined +#if defined(MICROPY_HW_CAN1_TX) || defined(MICROPY_HW_CAN2_TX) +#define MICROPY_HW_ENABLE_CAN (1) +#else +#define MICROPY_HW_ENABLE_CAN (0) +#endif + +// Pin definition header file +#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" + +// D-cache clean/invalidate helpers +#if __DCACHE_PRESENT == 1 +#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) \ + (SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), \ + ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) +#define MP_HAL_CLEAN_DCACHE(addr, size) \ + (SCB_CleanDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), \ + ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) +#else +#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) +#define MP_HAL_CLEAN_DCACHE(addr, size) +#endif + +#define MICROPY_HW_USES_BOOTLOADER (MICROPY_HW_VTOR != 0x08000000) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 51d4425616..a038664e83 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -29,6 +29,7 @@ // board specific definitions #include "mpconfigboard.h" +#include "mpconfigboard_common.h" // memory allocation policies #define MICROPY_ALLOC_PATH_MAX (128) @@ -75,10 +76,14 @@ #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_SCHEDULER_DEPTH (8) #define MICROPY_VFS (1) +#ifndef MICROPY_VFS_FAT #define MICROPY_VFS_FAT (1) +#endif // control over Python builtins #define MICROPY_PY_FUNCTION_ATTRS (1) +#define MICROPY_PY_DESCRIPTORS (1) +#define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_STR_CENTER (1) #define MICROPY_PY_BUILTINS_STR_PARTITION (1) @@ -86,9 +91,11 @@ #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_COMPILE (1) #define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) #define MICROPY_PY_BUILTINS_INPUT (1) #define MICROPY_PY_BUILTINS_POW3 (1) #define MICROPY_PY_BUILTINS_HELP (1) @@ -96,11 +103,13 @@ #define MICROPY_PY_BUILTINS_HELP_MODULES (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) #define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO (1) -#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_IO_IOBASE (1) +#define MICROPY_PY_IO_FILEIO (MICROPY_VFS_FAT) // because mp_type_fileio/textio point to fatfs impl #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_STDFILES (1) @@ -131,13 +140,15 @@ #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new #define MICROPY_PY_MACHINE_I2C (1) +#if MICROPY_HW_ENABLE_HW_I2C #define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new +#endif #define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_MACHINE_SPI_MSB (SPI_FIRSTBIT_MSB) #define MICROPY_PY_MACHINE_SPI_LSB (SPI_FIRSTBIT_LSB) #define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hard_spi_make_new -#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0) -#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) #define MICROPY_PY_FRAMEBUF (1) #ifndef MICROPY_PY_USOCKET #define MICROPY_PY_USOCKET (1) @@ -154,8 +165,8 @@ #define MICROPY_FATFS_MULTI_PARTITION (1) // TODO these should be generic, not bound to fatfs -#define mp_type_fileio fatfs_type_fileio -#define mp_type_textio fatfs_type_textio +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio // use vfs's functions for import stat and builtin open #define mp_import_stat mp_vfs_import_stat @@ -182,12 +193,27 @@ extern const struct _mp_obj_module_t mp_module_usocket; extern const struct _mp_obj_module_t mp_module_network; extern const struct _mp_obj_module_t mp_module_onewire; -#if MICROPY_PY_USOCKET +#if MICROPY_PY_STM +#define STM_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, +#else +#define STM_BUILTIN_MODULE +#endif + +#if MICROPY_PY_USOCKET && MICROPY_PY_LWIP +// usocket implementation provided by lwIP +#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) }, +#define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_lwip) }, +#define SOCKET_POLL extern void pyb_lwip_poll(void); pyb_lwip_poll(); +#elif MICROPY_PY_USOCKET +// usocket implementation provided by skeleton wrapper #define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, #define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) }, +#define SOCKET_POLL #else +// no usocket module #define SOCKET_BUILTIN_MODULE #define SOCKET_BUILTIN_MODULE_WEAK_LINKS +#define SOCKET_POLL #endif #if MICROPY_PY_NETWORK @@ -199,7 +225,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ - { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, \ + STM_BUILTIN_MODULE \ { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos) }, \ { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \ SOCKET_BUILTIN_MODULE \ @@ -229,21 +255,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&machine_module) }, \ { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ - { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, \ - -#if defined(MCU_SERIES_F7) -#define PYB_EXTI_NUM_VECTORS (24) -#define MICROPY_HW_MAX_TIMER (17) -#define MICROPY_HW_MAX_UART (8) -#elif defined(MCU_SERIES_L4) -#define PYB_EXTI_NUM_VECTORS (23) -#define MICROPY_HW_MAX_TIMER (17) -#define MICROPY_HW_MAX_UART (6) -#else -#define PYB_EXTI_NUM_VECTORS (23) -#define MICROPY_HW_MAX_TIMER (14) -#define MICROPY_HW_MAX_UART (6) -#endif + STM_BUILTIN_MODULE \ #define MP_STATE_PORT MP_STATE_VM @@ -299,8 +311,6 @@ typedef long mp_off_t; // value from disable_irq back to enable_irq. If you really need // to know the machine-specific values, see irq.h. -#include STM32_HAL_H - static inline void enable_irq(mp_uint_t state) { __set_PRIMASK(state); } @@ -319,6 +329,7 @@ static inline mp_uint_t disable_irq(void) { do { \ extern void mp_handle_pending(void); \ mp_handle_pending(); \ + SOCKET_POLL \ if (pyb_thread_enabled) { \ MP_THREAD_GIL_EXIT(); \ pyb_thread_yield(); \ @@ -334,6 +345,7 @@ static inline mp_uint_t disable_irq(void) { do { \ extern void mp_handle_pending(void); \ mp_handle_pending(); \ + SOCKET_POLL \ __WFI(); \ } while (0); @@ -351,12 +363,5 @@ static inline mp_uint_t disable_irq(void) { #define free(p) m_free(p) #define realloc(p, n) m_realloc(p, n) -// see stm32f4XX_hal_conf.h USE_USB_FS & USE_USB_HS -// at the moment only USB_FS is supported -#define USE_DEVICE_MODE -//#define USE_HOST_MODE - // We need to provide a declaration/definition of alloca() #include - -#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h" diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index e9c4f28f79..a2f8e412ee 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -7,8 +7,6 @@ #include "usb.h" #include "uart.h" -bool mp_hal_ticks_cpu_enabled = false; - // this table converts from HAL_StatusTypeDef to POSIX errno const byte mp_hal_status_to_errno_table[4] = { [HAL_OK] = 0, @@ -33,10 +31,13 @@ int mp_hal_stdin_rx_chr(void) { #endif #endif + #if MICROPY_HW_ENABLE_USB byte c; if (usb_vcp_recv_byte(&c) != 0) { return c; - } else if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) { + } + #endif + if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) { return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart)); } int dupterm_c = mp_uos_dupterm_rx_chr(); @@ -58,9 +59,11 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) { #if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD lcd_print_strn(str, len); #endif + #if MICROPY_HW_ENABLE_USB if (usb_vcp_is_enabled()) { usb_vcp_send_strn(str, len); } + #endif mp_uos_dupterm_tx_strn(str, len); } @@ -84,8 +87,9 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { } } +#if __CORTEX_M >= 0x03 void mp_hal_ticks_cpu_enable(void) { - if (!mp_hal_ticks_cpu_enabled) { + if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; #if defined(__CORTEX_M) && __CORTEX_M == 7 // on Cortex-M7 we must unlock the DWT before writing to its registers @@ -93,61 +97,38 @@ void mp_hal_ticks_cpu_enable(void) { #endif DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - mp_hal_ticks_cpu_enabled = true; } } +#endif void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { - if (0) { - #ifdef __GPIOA_CLK_ENABLE - } else if (gpio == GPIOA) { - __GPIOA_CLK_ENABLE(); - #endif - #ifdef __GPIOB_CLK_ENABLE - } else if (gpio == GPIOB) { - __GPIOB_CLK_ENABLE(); - #endif - #ifdef __GPIOC_CLK_ENABLE - } else if (gpio == GPIOC) { - __GPIOC_CLK_ENABLE(); - #endif - #ifdef __GPIOD_CLK_ENABLE - } else if (gpio == GPIOD) { - __GPIOD_CLK_ENABLE(); - #endif - #ifdef __GPIOE_CLK_ENABLE - } else if (gpio == GPIOE) { - __GPIOE_CLK_ENABLE(); - #endif - #if defined(GPIOF) && defined(__GPIOF_CLK_ENABLE) - } else if (gpio == GPIOF) { - __GPIOF_CLK_ENABLE(); - #endif - #if defined(GPIOG) && defined(__GPIOG_CLK_ENABLE) - } else if (gpio == GPIOG) { - #if defined(STM32L476xx) || defined(STM32L486xx) + #if defined(STM32L476xx) || defined(STM32L496xx) + if (gpio == GPIOG) { // Port G pins 2 thru 15 are powered using VddIO2 on these MCUs. HAL_PWREx_EnableVddIO2(); - #endif - __GPIOG_CLK_ENABLE(); - #endif - #ifdef __GPIOH_CLK_ENABLE - } else if (gpio == GPIOH) { - __GPIOH_CLK_ENABLE(); - #endif - #if defined(GPIOI) && defined(__GPIOI_CLK_ENABLE) - } else if (gpio == GPIOI) { - __GPIOI_CLK_ENABLE(); - #endif - #if defined(GPIOJ) && defined(__GPIOJ_CLK_ENABLE) - } else if (gpio == GPIOJ) { - __GPIOJ_CLK_ENABLE(); - #endif - #if defined(GPIOK) && defined(__GPIOK_CLK_ENABLE) - } else if (gpio == GPIOK) { - __GPIOK_CLK_ENABLE(); - #endif } + #endif + + // This logic assumes that all the GPIOx_EN bits are adjacent and ordered in one register + + #if defined(STM32F0) + #define AHBxENR AHBENR + #define AHBxENR_GPIOAEN_Pos RCC_AHBENR_GPIOAEN_Pos + #elif defined(STM32F4) || defined(STM32F7) + #define AHBxENR AHB1ENR + #define AHBxENR_GPIOAEN_Pos RCC_AHB1ENR_GPIOAEN_Pos + #elif defined(STM32H7) + #define AHBxENR AHB4ENR + #define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos + #elif defined(STM32L4) + #define AHBxENR AHB2ENR + #define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos + #endif + + uint32_t gpio_idx = ((uint32_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE); + RCC->AHBxENR |= 1 << (AHBxENR_GPIOAEN_Pos + gpio_idx); + volatile uint32_t tmp = RCC->AHBxENR; // Delay after enabling clock + (void)tmp; } void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, uint32_t alt) { @@ -155,7 +136,13 @@ void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, u uint32_t pin = pin_obj->pin; mp_hal_gpio_clock_enable(gpio); gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin)); + #if defined(GPIO_ASCR_ASC0) + // The L4 has a special analog switch to connect the GPIO to the ADC + gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | (((mode >> 2) & 1) << pin); + gpio->ASCR = (gpio->ASCR & ~(1 << pin)) | ((mode >> 3) & 1) << pin; + #else gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin); + #endif gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (2 << (2 * pin)); // full speed gpio->PUPDR = (gpio->PUPDR & ~(3 << (2 * pin))) | (pull << (2 * pin)); gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); @@ -169,3 +156,9 @@ bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, u mp_hal_pin_config(pin, mode, pull, af->idx); return true; } + +void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed) { + GPIO_TypeDef *gpio = pin_obj->gpio; + uint32_t pin = pin_obj->pin; + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << (2 * pin))) | (speed << (2 * pin)); +} diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 939df0b3d2..72413c04c7 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -2,24 +2,6 @@ #include STM32_HAL_H #include "pin.h" -// The unique id address differs per MCU. Ideally this define should -// go in some MCU-specific header, but for now it lives here. -#if defined(MCU_SERIES_F4) -#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) -#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) -#define MP_HAL_CLEAN_DCACHE(addr, size) -#elif defined(MCU_SERIES_F7) -#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff0f420) -#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) (SCB_CleanInvalidateDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) -#define MP_HAL_CLEAN_DCACHE(addr, size) (SCB_CleanDCache_by_Addr((uint32_t*)((uint32_t)addr & ~0x1f), ((uint32_t)((uint8_t*)addr + size + 0x1f) & ~0x1f) - ((uint32_t)addr & ~0x1f))) -#elif defined(MCU_SERIES_L4) -#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7590) -#define MP_HAL_CLEANINVALIDATE_DCACHE(addr, size) -#define MP_HAL_CLEAN_DCACHE(addr, size) -#else -#error mphalport.h: Unrecognized MCU_SERIES -#endif - extern const unsigned char mp_hal_status_to_errno_table[4]; NORETURN void mp_hal_raise(HAL_StatusTypeDef status); @@ -29,17 +11,26 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable #include "irq.h" +#if __CORTEX_M == 0 +// Don't have raise_irq_pri on Cortex-M0 so keep IRQs enabled to have SysTick timing +#define mp_hal_quiet_timing_enter() (1) +#define mp_hal_quiet_timing_exit(irq_state) (void)(irq_state) +#else #define mp_hal_quiet_timing_enter() raise_irq_pri(1) #define mp_hal_quiet_timing_exit(irq_state) restore_irq_pri(irq_state) +#endif #define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) -extern bool mp_hal_ticks_cpu_enabled; void mp_hal_ticks_cpu_enable(void); static inline mp_uint_t mp_hal_ticks_cpu(void) { - if (!mp_hal_ticks_cpu_enabled) { + #if __CORTEX_M == 0 + return 0; + #else + if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { mp_hal_ticks_cpu_enable(); } return DWT->CYCCNT; + #endif } // C-level pin HAL @@ -51,6 +42,11 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { #define MP_HAL_PIN_MODE_OUTPUT (1) #define MP_HAL_PIN_MODE_ALT (2) #define MP_HAL_PIN_MODE_ANALOG (3) +#if defined(GPIO_ASCR_ASC0) +#define MP_HAL_PIN_MODE_ADC (11) +#else +#define MP_HAL_PIN_MODE_ADC (3) +#endif #define MP_HAL_PIN_MODE_OPEN_DRAIN (5) #define MP_HAL_PIN_MODE_ALT_OPEN_DRAIN (6) #define MP_HAL_PIN_PULL_NONE (GPIO_NOPULL) @@ -63,8 +59,13 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { #define mp_hal_pin_input(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0) #define mp_hal_pin_output(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0) #define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 0) +#if defined(STM32H7) +#define mp_hal_pin_high(p) (((p)->gpio->BSRRL) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->BSRRH) = (p)->pin_mask) +#else #define mp_hal_pin_high(p) (((p)->gpio->BSRR) = (p)->pin_mask) #define mp_hal_pin_low(p) (((p)->gpio->BSRR) = ((p)->pin_mask << 16)) +#endif #define mp_hal_pin_od_low(p) mp_hal_pin_low(p) #define mp_hal_pin_od_high(p) mp_hal_pin_high(p) #define mp_hal_pin_read(p) (((p)->gpio->IDR >> (p)->pin) & 1) @@ -73,3 +74,4 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); void mp_hal_pin_config(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint32_t alt); bool mp_hal_pin_config_alt(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint8_t fn, uint8_t unit); +void mp_hal_pin_config_speed(mp_hal_pin_obj_t pin_obj, uint32_t speed); diff --git a/ports/stm32/network_wiznet5k.c b/ports/stm32/network_wiznet5k.c new file mode 100644 index 0000000000..9db42b7874 --- /dev/null +++ b/ports/stm32/network_wiznet5k.c @@ -0,0 +1,417 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/runtime.h" +#include "py/mphal.h" +#include "spi.h" +#include "modnetwork.h" + +#if MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP + +#include "drivers/wiznet5k/ethernet/socket.h" +#include "lwip/err.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" +#include "netif/etharp.h" + +/*******************************************************************************/ +// Wiznet5k Ethernet driver in MACRAW mode + +typedef struct _wiznet5k_obj_t { + mod_network_nic_type_t base; + mp_uint_t cris_state; + const spi_t *spi; + mp_hal_pin_obj_t cs; + mp_hal_pin_obj_t rst; + uint8_t eth_frame[1514]; + struct netif netif; + struct dhcp dhcp_struct; +} wiznet5k_obj_t; + +// Global object holding the Wiznet5k state +STATIC wiznet5k_obj_t wiznet5k_obj; + +STATIC void wiznet5k_lwip_init(wiznet5k_obj_t *self); +STATIC void wiznet5k_lwip_poll(void *self_in, struct netif *netif); + +STATIC void wiz_cris_enter(void) { + wiznet5k_obj.cris_state = MICROPY_BEGIN_ATOMIC_SECTION(); +} + +STATIC void wiz_cris_exit(void) { + MICROPY_END_ATOMIC_SECTION(wiznet5k_obj.cris_state); +} + +STATIC void wiz_cs_select(void) { + mp_hal_pin_low(wiznet5k_obj.cs); +} + +STATIC void wiz_cs_deselect(void) { + mp_hal_pin_high(wiznet5k_obj.cs); +} + +STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) { + HAL_StatusTypeDef status = HAL_SPI_Receive(wiznet5k_obj.spi->spi, buf, len, 5000); + (void)status; +} + +STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) { + HAL_StatusTypeDef status = HAL_SPI_Transmit(wiznet5k_obj.spi->spi, (uint8_t*)buf, len, 5000); + (void)status; +} + +STATIC void wiznet5k_init(void) { + // SPI configuration + SPI_InitTypeDef *init = &wiznet5k_obj.spi->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle + init->CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; // unused + spi_init(wiznet5k_obj.spi, false); + + mp_hal_pin_output(wiznet5k_obj.cs); + mp_hal_pin_output(wiznet5k_obj.rst); + + // Reset the chip + mp_hal_pin_low(wiznet5k_obj.rst); + mp_hal_delay_ms(1); // datasheet says 2us + mp_hal_pin_high(wiznet5k_obj.rst); + mp_hal_delay_ms(150); // datasheet says 150ms + + // Set physical interface callbacks + reg_wizchip_cris_cbfunc(wiz_cris_enter, wiz_cris_exit); + reg_wizchip_cs_cbfunc(wiz_cs_select, wiz_cs_deselect); + reg_wizchip_spi_cbfunc(wiz_spi_read, wiz_spi_write); + + // Configure 16k buffers for fast MACRAW + uint8_t sn_size[16] = {16, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0}; + ctlwizchip(CW_INIT_WIZCHIP, sn_size); + + // Seems we need a small delay after init + mp_hal_delay_ms(250); + + // Hook the Wiznet into lwIP + wiznet5k_lwip_init(&wiznet5k_obj); +} + +STATIC void wiznet5k_deinit(void) { + for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { + if (netif == &wiznet5k_obj.netif) { + netif_remove(netif); + netif->flags = 0; + break; + } + } +} + +STATIC void wiznet5k_get_mac_address(wiznet5k_obj_t *self, uint8_t mac[6]) { + (void)self; + getSHAR(mac); +} + +STATIC void wiznet5k_send_ethernet(wiznet5k_obj_t *self, size_t len, const uint8_t *buf) { + uint8_t ip[4] = {1, 1, 1, 1}; // dummy + int ret = WIZCHIP_EXPORT(sendto)(0, (byte*)buf, len, ip, 11); // dummy port + if (ret != len) { + printf("wiznet5k_send_ethernet: fatal error %d\n", ret); + netif_set_link_down(&self->netif); + netif_set_down(&self->netif); + } +} + +// Stores the frame in self->eth_frame and returns number of bytes in the frame, 0 for no frame +STATIC uint16_t wiznet5k_recv_ethernet(wiznet5k_obj_t *self) { + uint16_t len = getSn_RX_RSR(0); + if (len == 0) { + return 0; + } + + byte ip[4]; + uint16_t port; + int ret = WIZCHIP_EXPORT(recvfrom)(0, self->eth_frame, 1514, ip, &port); + if (ret <= 0) { + printf("wiznet5k_lwip_poll: fatal error len=%u ret=%d\n", len, ret); + netif_set_link_down(&self->netif); + netif_set_down(&self->netif); + return 0; + } + + return ret; +} + +/*******************************************************************************/ +// Wiznet5k lwIP interface + +STATIC err_t wiznet5k_netif_output(struct netif *netif, struct pbuf *p) { + wiznet5k_obj_t *self = netif->state; + pbuf_copy_partial(p, self->eth_frame, p->tot_len, 0); + wiznet5k_send_ethernet(self, p->tot_len, self->eth_frame); + return ERR_OK; +} + +STATIC err_t wiznet5k_netif_init(struct netif *netif) { + netif->linkoutput = wiznet5k_netif_output; + netif->output = etharp_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; + wiznet5k_get_mac_address(netif->state, netif->hwaddr); + netif->hwaddr_len = sizeof(netif->hwaddr); + int ret = WIZCHIP_EXPORT(socket)(0, Sn_MR_MACRAW, 0, 0); + if (ret != 0) { + printf("WIZNET fatal error in netifinit: %d\n", ret); + return ERR_IF; + } + + // Enable MAC filtering so we only get frames destined for us, to reduce load on lwIP + setSn_MR(0, getSn_MR(0) | Sn_MR_MFEN); + + return ERR_OK; +} + +STATIC void wiznet5k_lwip_init(wiznet5k_obj_t *self) { + ip_addr_t ipconfig[4]; + ipconfig[0].addr = 0; + ipconfig[1].addr = 0; + ipconfig[2].addr = 0; + ipconfig[3].addr = 0; + netif_add(&self->netif, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, wiznet5k_netif_init, ethernet_input); + self->netif.name[0] = 'e'; + self->netif.name[1] = '0'; + netif_set_default(&self->netif); + dns_setserver(0, &ipconfig[3]); + dhcp_set_struct(&self->netif, &self->dhcp_struct); + // Setting NETIF_FLAG_UP then clearing it is a workaround for dhcp_start and the + // LWIP_DHCP_CHECK_LINK_UP option, so that the DHCP client schedules itself to + // automatically start when the interface later goes up. + self->netif.flags |= NETIF_FLAG_UP; + dhcp_start(&self->netif); + self->netif.flags &= ~NETIF_FLAG_UP; +} + +STATIC void wiznet5k_lwip_poll(void *self_in, struct netif *netif) { + wiznet5k_obj_t *self = self_in; + uint16_t len; + while ((len = wiznet5k_recv_ethernet(self)) > 0) { + struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (p != NULL) { + pbuf_take(p, self->eth_frame, len); + if (self->netif.input(p, &self->netif) != ERR_OK) { + pbuf_free(p); + } + } + } +} + +/*******************************************************************************/ +// MicroPython bindings + +// WIZNET5K([spi, pin_cs, pin_rst]) +STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 3, 3, false); + + const spi_t *spi = spi_from_mp_obj(args[0]); + mp_hal_pin_obj_t cs = pin_find(args[1]); + mp_hal_pin_obj_t rst = pin_find(args[2]); + + // Access the existing object, if it has been constructed with the same hardware interface + if (wiznet5k_obj.base.base.type == &mod_network_nic_type_wiznet5k) { + if (!(wiznet5k_obj.spi == spi && wiznet5k_obj.cs == cs && wiznet5k_obj.rst == rst + && wiznet5k_obj.netif.flags != 0)) { + wiznet5k_deinit(); + } + } + + // Init the wiznet5k object + wiznet5k_obj.base.base.type = &mod_network_nic_type_wiznet5k; + wiznet5k_obj.base.poll_callback = wiznet5k_lwip_poll; + wiznet5k_obj.cris_state = 0; + wiznet5k_obj.spi = spi; + wiznet5k_obj.cs = cs; + wiznet5k_obj.rst = rst; + + // Return wiznet5k object + return MP_OBJ_FROM_PTR(&wiznet5k_obj); +} + +STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) { + (void)self_in; + printf("Wiz CREG:"); + for (int i = 0; i < 0x50; ++i) { + if (i % 16 == 0) { + printf("\n %04x:", i); + } + #if MICROPY_PY_WIZNET5K == 5200 + uint32_t reg = i; + #else + uint32_t reg = _W5500_IO_BASE_ | i << 8; + #endif + printf(" %02x", WIZCHIP_READ(reg)); + } + for (int sn = 0; sn < 4; ++sn) { + printf("\nWiz SREG[%d]:", sn); + for (int i = 0; i < 0x30; ++i) { + if (i % 16 == 0) { + printf("\n %04x:", i); + } + #if MICROPY_PY_WIZNET5K == 5200 + uint32_t reg = WIZCHIP_SREG_ADDR(sn, i); + #else + uint32_t reg = _W5500_IO_BASE_ | i << 8 | WIZCHIP_SREG_BLOCK(sn) << 3; + #endif + printf(" %02x", WIZCHIP_READ(reg)); + } + } + printf("\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_regs_obj, wiznet5k_regs); + +STATIC mp_obj_t wiznet5k_isconnected(mp_obj_t self_in) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool( + wizphy_getphylink() == PHY_LINK_ON + && (self->netif.flags & NETIF_FLAG_UP) + && self->netif.ip_addr.addr != 0 + ); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_isconnected_obj, wiznet5k_isconnected); + +STATIC mp_obj_t wiznet5k_active(size_t n_args, const mp_obj_t *args) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + return mp_obj_new_bool(self->netif.flags & NETIF_FLAG_UP); + } else { + if (mp_obj_is_true(args[1])) { + if (!(self->netif.flags & NETIF_FLAG_UP)) { + wiznet5k_init(); + netif_set_link_up(&self->netif); + netif_set_up(&self->netif); + } + } else { + if (self->netif.flags & NETIF_FLAG_UP) { + netif_set_down(&self->netif); + netif_set_link_down(&self->netif); + wiznet5k_deinit(); + } + } + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_active_obj, 1, 2, wiznet5k_active); + +STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + return mod_network_nic_ifconfig(&self->netif, n_args - 1, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ifconfig_obj, 1, 2, wiznet5k_ifconfig); + +STATIC mp_obj_t wiznet5k_status(size_t n_args, const mp_obj_t *args) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + (void)self; + + if (n_args == 1) { + // No arguments: return link status + if (self->netif.flags && wizphy_getphylink() == PHY_LINK_ON) { + if ((self->netif.flags & NETIF_FLAG_UP) && self->netif.ip_addr.addr != 0) { + return MP_OBJ_NEW_SMALL_INT(2); + } else { + return MP_OBJ_NEW_SMALL_INT(1); + } + } else { + return MP_OBJ_NEW_SMALL_INT(0); + } + } + + mp_raise_ValueError("unknown config param"); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_status_obj, 1, 2, wiznet5k_status); + +STATIC mp_obj_t wiznet5k_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + if (kwargs->used == 0) { + // Get config value + if (n_args != 2) { + mp_raise_TypeError("must query one param"); + } + + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_mac: { + uint8_t buf[6]; + wiznet5k_get_mac_address(self, buf); + return mp_obj_new_bytes(buf, 6); + } + default: + mp_raise_ValueError("unknown config param"); + } + } else { + // Set config value(s) + if (n_args != 1) { + mp_raise_TypeError("can't specify pos and kw args"); + } + mp_raise_ValueError("unknown config param"); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wiznet5k_config_obj, 1, wiznet5k_config); + +STATIC mp_obj_t send_ethernet_wrapper(mp_obj_t self_in, mp_obj_t buf_in) { + wiznet5k_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t buf; + mp_get_buffer_raise(buf_in, &buf, MP_BUFFER_READ); + wiznet5k_send_ethernet(self, buf.len, buf.buf); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(send_ethernet_obj, send_ethernet_wrapper); + +STATIC const mp_rom_map_elem_t wiznet5k_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_regs), MP_ROM_PTR(&wiznet5k_regs_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wiznet5k_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&wiznet5k_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wiznet5k_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&wiznet5k_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&wiznet5k_config_obj) }, + + { MP_ROM_QSTR(MP_QSTR_send_ethernet), MP_ROM_PTR(&send_ethernet_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table); + +const mp_obj_type_t mod_network_nic_type_wiznet5k = { + { &mp_type_type }, + .name = MP_QSTR_WIZNET5K, + .make_new = wiznet5k_make_new, + .locals_dict = (mp_obj_dict_t*)&wiznet5k_locals_dict, +}; + +#endif // MICROPY_PY_WIZNET5K && MICROPY_PY_LWIP diff --git a/ports/stm32/pendsv.c b/ports/stm32/pendsv.c index 0aeb1a6dcf..b5fe42f70d 100644 --- a/ports/stm32/pendsv.c +++ b/ports/stm32/pendsv.c @@ -40,7 +40,7 @@ void *pendsv_object; void pendsv_init(void) { // set PendSV interrupt at lowest priority - HAL_NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV, IRQ_SUBPRI_PENDSV); + NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV); } // Call this function to raise a pending exception during an interrupt. diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index 6a9eb0d794..0d9fde6878 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_PENDSV_H -#define MICROPY_INCLUDED_STMHAL_PENDSV_H +#ifndef MICROPY_INCLUDED_STM32_PENDSV_H +#define MICROPY_INCLUDED_STM32_PENDSV_H void pendsv_init(void); void pendsv_kbd_intr(void); @@ -33,4 +33,4 @@ void pendsv_kbd_intr(void); // prelude for this function void pendsv_isr_handler(void) __attribute__((naked)); -#endif // MICROPY_INCLUDED_STMHAL_PENDSV_H +#endif // MICROPY_INCLUDED_STM32_PENDSV_H diff --git a/ports/stm32/pin.c b/ports/stm32/pin.c index ee2d846469..fbd3f00c17 100644 --- a/ports/stm32/pin.c +++ b/ports/stm32/pin.c @@ -376,7 +376,7 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, size_t n_args, const GPIO_InitStructure.Pin = self->pin_mask; GPIO_InitStructure.Mode = mode; GPIO_InitStructure.Pull = pull; - GPIO_InitStructure.Speed = GPIO_SPEED_FAST; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStructure.Alternate = af; HAL_GPIO_Init(self->gpio, &GPIO_InitStructure); diff --git a/ports/stm32/pin.h b/ports/stm32/pin.h index 90de79e5ce..ea57b0a274 100644 --- a/ports/stm32/pin.h +++ b/ports/stm32/pin.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_PIN_H -#define MICROPY_INCLUDED_STMHAL_PIN_H +#ifndef MICROPY_INCLUDED_STM32_PIN_H +#define MICROPY_INCLUDED_STM32_PIN_H // This file requires pin_defs_xxx.h (which has port specific enums and // defines, so we include it here. It should never be included directly @@ -39,12 +39,7 @@ typedef struct { uint8_t fn; uint8_t unit; uint8_t type; - - union { - void *reg; - - PIN_DEFS_PORT_AF_UNION - }; + void *reg; // The peripheral associated with this AF } pin_af_obj_t; typedef struct { @@ -63,6 +58,9 @@ typedef struct { extern const mp_obj_type_t pin_type; extern const mp_obj_type_t pin_af_type; +// Include all of the individual pin objects +#include "genhdr/pins.h" + typedef struct { const char *name; const pin_obj_t *pin; @@ -97,4 +95,4 @@ const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit); const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx); const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name); -#endif // MICROPY_INCLUDED_STMHAL_PIN_H +#endif // MICROPY_INCLUDED_STM32_PIN_H diff --git a/ports/stm32/pin_defs_stm32.h b/ports/stm32/pin_defs_stm32.h index c5b2862835..5c5c6be697 100644 --- a/ports/stm32/pin_defs_stm32.h +++ b/ports/stm32/pin_defs_stm32.h @@ -49,6 +49,7 @@ enum { AF_FN_SPI, AF_FN_I2S, AF_FN_SDMMC, + AF_FN_CAN, }; enum { @@ -93,6 +94,9 @@ enum { AF_PIN_TYPE_SDMMC_D1, AF_PIN_TYPE_SDMMC_D2, AF_PIN_TYPE_SDMMC_D3, + + AF_PIN_TYPE_CAN_TX = 0, + AF_PIN_TYPE_CAN_RX, }; // The HAL uses a slightly different naming than we chose, so we provide @@ -115,17 +119,5 @@ enum { PIN_ADC3 = (1 << 2), }; -// Note that SPI and I2S are really the same peripheral as far as the HAL -// is concerned, so there is no I2S_TypeDef. -// We use void* for SDMMC because not all MCUs have the SDMMC_TypeDef type. -#define PIN_DEFS_PORT_AF_UNION \ - TIM_TypeDef *TIM; \ - I2C_TypeDef *I2C; \ - USART_TypeDef *USART; \ - USART_TypeDef *UART; \ - SPI_TypeDef *SPI;\ - SPI_TypeDef *I2S; \ - void *SDMMC; \ - typedef GPIO_TypeDef pin_gpio_t; diff --git a/ports/stm32/portmodules.h b/ports/stm32/portmodules.h index b575109b89..81cb7fd04a 100644 --- a/ports/stm32/portmodules.h +++ b/ports/stm32/portmodules.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_PORTMODULES_H -#define MICROPY_INCLUDED_STMHAL_PORTMODULES_H +#ifndef MICROPY_INCLUDED_STM32_PORTMODULES_H +#define MICROPY_INCLUDED_STM32_PORTMODULES_H extern const mp_obj_module_t pyb_module; extern const mp_obj_module_t stm_module; @@ -40,4 +40,4 @@ MP_DECLARE_CONST_FUN_OBJ_1(time_sleep_us_obj); MP_DECLARE_CONST_FUN_OBJ_0(mod_os_sync_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj); -#endif // MICROPY_INCLUDED_STMHAL_PORTMODULES_H +#endif // MICROPY_INCLUDED_STM32_PORTMODULES_H diff --git a/ports/stm32/pyb_i2c.c b/ports/stm32/pyb_i2c.c new file mode 100644 index 0000000000..33aaa48cbb --- /dev/null +++ b/ports/stm32/pyb_i2c.c @@ -0,0 +1,1068 @@ +/* + * 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 + +#include "py/runtime.h" +#include "py/mphal.h" +#include "irq.h" +#include "pin.h" +#include "bufhelper.h" +#include "dma.h" +#include "i2c.h" + +#if MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C + +/// \moduleref pyb +/// \class I2C - a two-wire serial protocol +/// +/// I2C is a two-wire protocol for communicating between devices. At the physical +/// level it consists of 2 wires: SCL and SDA, the clock and data lines respectively. +/// +/// I2C objects are created attached to a specific bus. They can be initialised +/// when created, or initialised later on: +/// +/// from pyb import I2C +/// +/// i2c = I2C(1) # create on bus 1 +/// i2c = I2C(1, I2C.MASTER) # create and init as a master +/// i2c.init(I2C.MASTER, baudrate=20000) # init as a master +/// i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address +/// i2c.deinit() # turn off the peripheral +/// +/// Printing the i2c object gives you information about its configuration. +/// +/// Basic methods for slave are send and recv: +/// +/// i2c.send('abc') # send 3 bytes +/// i2c.send(0x42) # send a single byte, given by the number +/// data = i2c.recv(3) # receive 3 bytes +/// +/// To receive inplace, first create a bytearray: +/// +/// data = bytearray(3) # create a buffer +/// i2c.recv(data) # receive 3 bytes, writing them into data +/// +/// You can specify a timeout (in ms): +/// +/// i2c.send(b'123', timeout=2000) # timout after 2 seconds +/// +/// A master must specify the recipient's address: +/// +/// i2c.init(I2C.MASTER) +/// i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42 +/// i2c.send(b'456', addr=0x42) # keyword for address +/// +/// Master also has other methods: +/// +/// i2c.is_ready(0x42) # check if slave 0x42 is ready +/// i2c.scan() # scan for slaves on the bus, returning +/// # a list of valid addresses +/// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42, +/// # starting at address 2 in the slave +/// i2c.mem_write('abc', 0x42, 2, timeout=1000) +#define PYB_I2C_MASTER (0) +#define PYB_I2C_SLAVE (1) + +#define PYB_I2C_SPEED_STANDARD (100000L) +#define PYB_I2C_SPEED_FULL (400000L) +#define PYB_I2C_SPEED_FAST (1000000L) + +#if defined(MICROPY_HW_I2C1_SCL) +I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_I2C2_SCL) +I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_I2C3_SCL) +I2C_HandleTypeDef I2CHandle3 = {.Instance = NULL}; +#endif +#if defined(MICROPY_HW_I2C4_SCL) +I2C_HandleTypeDef I2CHandle4 = {.Instance = NULL}; +#endif + +STATIC bool pyb_i2c_use_dma[4]; + +const pyb_i2c_obj_t pyb_i2c_obj[] = { + #if defined(MICROPY_HW_I2C1_SCL) + {{&pyb_i2c_type}, &I2CHandle1, &dma_I2C_1_TX, &dma_I2C_1_RX, &pyb_i2c_use_dma[0]}, + #else + {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C2_SCL) + {{&pyb_i2c_type}, &I2CHandle2, &dma_I2C_2_TX, &dma_I2C_2_RX, &pyb_i2c_use_dma[1]}, + #else + {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C3_SCL) + {{&pyb_i2c_type}, &I2CHandle3, &dma_I2C_3_TX, &dma_I2C_3_RX, &pyb_i2c_use_dma[2]}, + #else + {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, + #endif + #if defined(MICROPY_HW_I2C4_SCL) + {{&pyb_i2c_type}, &I2CHandle4, &dma_I2C_4_TX, &dma_I2C_4_RX, &pyb_i2c_use_dma[3]}, + #else + {{&pyb_i2c_type}, NULL, NULL, NULL, NULL}, + #endif +}; + +#if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) + +// The STM32F0, F3, F7, H7 and L4 use a TIMINGR register rather than ClockSpeed and +// DutyCycle. + +#if defined(STM32F746xx) + +// The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant +// defined in the STM32F7Cube file Drivers/BSP/STM32F746G-Discovery/stm32f7456g_discovery.h +#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ + {PYB_I2C_SPEED_STANDARD, 0x40912732}, \ + {PYB_I2C_SPEED_FULL, 0x10911823}, \ + {PYB_I2C_SPEED_FAST, 0x00611116}, \ + } +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) + +#elif defined(STM32F722xx) || defined(STM32F723xx) \ + || defined(STM32F732xx) || defined(STM32F733xx) \ + || defined(STM32F767xx) || defined(STM32F769xx) + +// These timing values are for f_I2CCLK=54MHz and are only approximate +#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ + {PYB_I2C_SPEED_STANDARD, 0xb0420f13}, \ + {PYB_I2C_SPEED_FULL, 0x70330309}, \ + {PYB_I2C_SPEED_FAST, 0x50100103}, \ + } +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) + +#elif defined(STM32H7) + +// I2C TIMINGs obtained from the STHAL examples. +#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ + {PYB_I2C_SPEED_STANDARD, 0x40604E73}, \ + {PYB_I2C_SPEED_FULL, 0x00901954}, \ + {PYB_I2C_SPEED_FAST, 0x10810915}, \ + } +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) + +#elif defined(STM32L4) + +// The value 0x90112626 was obtained from the DISCOVERY_I2C1_TIMING constant +// defined in the STM32L4Cube file Drivers/BSP/STM32L476G-Discovery/stm32l476g_discovery.h +#define MICROPY_HW_I2C_BAUDRATE_TIMING {{PYB_I2C_SPEED_STANDARD, 0x90112626}} +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_STANDARD) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_STANDARD) + +#else +#error "no I2C timings for this MCU" +#endif + +STATIC const struct { + uint32_t baudrate; + uint32_t timing; +} pyb_i2c_baudrate_timing[] = MICROPY_HW_I2C_BAUDRATE_TIMING; + +#define NUM_BAUDRATE_TIMINGS MP_ARRAY_SIZE(pyb_i2c_baudrate_timing) + +STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { + for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) { + if (pyb_i2c_baudrate_timing[i].baudrate == baudrate) { + init->Timing = pyb_i2c_baudrate_timing[i].timing; + return; + } + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Unsupported I2C baudrate: %u", baudrate)); +} + +uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) { + for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) { + if (pyb_i2c_baudrate_timing[i].timing == i2c->Init.Timing) { + return pyb_i2c_baudrate_timing[i].baudrate; + } + } + return 0; +} + +#else + +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FULL) + +STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { + init->ClockSpeed = baudrate; + init->DutyCycle = I2C_DUTYCYCLE_16_9; +} + +uint32_t pyb_i2c_get_baudrate(I2C_HandleTypeDef *i2c) { + uint32_t pfreq = i2c->Instance->CR2 & 0x3f; + uint32_t ccr = i2c->Instance->CCR & 0xfff; + if (i2c->Instance->CCR & 0x8000) { + // Fast mode, assume duty cycle of 16/9 + return pfreq * 40000 / ccr; + } else { + // Standard mode + return pfreq * 500000 / ccr; + } +} + +#endif + +void i2c_init0(void) { + // Initialise the I2C handles. + // The structs live on the BSS so all other fields will be zero after a reset. + #if defined(MICROPY_HW_I2C1_SCL) + I2CHandle1.Instance = I2C1; + #endif + #if defined(MICROPY_HW_I2C2_SCL) + I2CHandle2.Instance = I2C2; + #endif + #if defined(MICROPY_HW_I2C3_SCL) + I2CHandle3.Instance = I2C3; + #endif + #if defined(MICROPY_HW_I2C4_SCL) + I2CHandle4.Instance = I2C4; + #endif +} + +void pyb_i2c_init(I2C_HandleTypeDef *i2c) { + int i2c_unit; + const pin_obj_t *scl_pin; + const pin_obj_t *sda_pin; + + if (0) { + #if defined(MICROPY_HW_I2C1_SCL) + } else if (i2c == &I2CHandle1) { + i2c_unit = 1; + scl_pin = MICROPY_HW_I2C1_SCL; + sda_pin = MICROPY_HW_I2C1_SDA; + __HAL_RCC_I2C1_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_I2C2_SCL) + } else if (i2c == &I2CHandle2) { + i2c_unit = 2; + scl_pin = MICROPY_HW_I2C2_SCL; + sda_pin = MICROPY_HW_I2C2_SDA; + __HAL_RCC_I2C2_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_I2C3_SCL) + } else if (i2c == &I2CHandle3) { + i2c_unit = 3; + scl_pin = MICROPY_HW_I2C3_SCL; + sda_pin = MICROPY_HW_I2C3_SDA; + __HAL_RCC_I2C3_CLK_ENABLE(); + #endif + #if defined(MICROPY_HW_I2C4_SCL) + } else if (i2c == &I2CHandle4) { + i2c_unit = 4; + scl_pin = MICROPY_HW_I2C4_SCL; + sda_pin = MICROPY_HW_I2C4_SDA; + __HAL_RCC_I2C4_CLK_ENABLE(); + #endif + } else { + // I2C does not exist for this board (shouldn't get here, should be checked by caller) + return; + } + + // init the GPIO lines + uint32_t mode = MP_HAL_PIN_MODE_ALT_OPEN_DRAIN; + uint32_t pull = MP_HAL_PIN_PULL_NONE; // have external pull-up resistors on both lines + mp_hal_pin_config_alt(scl_pin, mode, pull, AF_FN_I2C, i2c_unit); + mp_hal_pin_config_alt(sda_pin, mode, pull, AF_FN_I2C, i2c_unit); + + // init the I2C device + if (HAL_I2C_Init(i2c) != HAL_OK) { + // init error + // TODO should raise an exception, but this function is not necessarily going to be + // called via Python, so may not be properly wrapped in an NLR handler + printf("OSError: HAL_I2C_Init failed\n"); + return; + } + + // invalidate the DMA channels so they are initialised on first use + const pyb_i2c_obj_t *self = &pyb_i2c_obj[i2c_unit - 1]; + dma_invalidate_channel(self->tx_dma_descr); + dma_invalidate_channel(self->rx_dma_descr); + + if (0) { + #if defined(MICROPY_HW_I2C1_SCL) + } else if (i2c->Instance == I2C1) { + HAL_NVIC_EnableIRQ(I2C1_EV_IRQn); + HAL_NVIC_EnableIRQ(I2C1_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C2_SCL) + } else if (i2c->Instance == I2C2) { + HAL_NVIC_EnableIRQ(I2C2_EV_IRQn); + HAL_NVIC_EnableIRQ(I2C2_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C3_SCL) + } else if (i2c->Instance == I2C3) { + HAL_NVIC_EnableIRQ(I2C3_EV_IRQn); + HAL_NVIC_EnableIRQ(I2C3_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C4_SCL) + } else if (i2c->Instance == I2C4) { + HAL_NVIC_EnableIRQ(I2C4_EV_IRQn); + HAL_NVIC_EnableIRQ(I2C4_ER_IRQn); + #endif + } +} + +void i2c_deinit(I2C_HandleTypeDef *i2c) { + HAL_I2C_DeInit(i2c); + if (0) { + #if defined(MICROPY_HW_I2C1_SCL) + } else if (i2c->Instance == I2C1) { + __HAL_RCC_I2C1_FORCE_RESET(); + __HAL_RCC_I2C1_RELEASE_RESET(); + __HAL_RCC_I2C1_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(I2C1_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C1_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C2_SCL) + } else if (i2c->Instance == I2C2) { + __HAL_RCC_I2C2_FORCE_RESET(); + __HAL_RCC_I2C2_RELEASE_RESET(); + __HAL_RCC_I2C2_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(I2C2_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C2_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C3_SCL) + } else if (i2c->Instance == I2C3) { + __HAL_RCC_I2C3_FORCE_RESET(); + __HAL_RCC_I2C3_RELEASE_RESET(); + __HAL_RCC_I2C3_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(I2C3_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C3_ER_IRQn); + #endif + #if defined(MICROPY_HW_I2C4_SCL) + } else if (i2c->Instance == I2C4) { + __HAL_RCC_I2C4_FORCE_RESET(); + __HAL_RCC_I2C4_RELEASE_RESET(); + __HAL_RCC_I2C4_CLK_DISABLE(); + HAL_NVIC_DisableIRQ(I2C4_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C4_ER_IRQn); + #endif + } +} + +void pyb_i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq) { + I2C_InitTypeDef *init = &self->i2c->Init; + + init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; + init->DualAddressMode = I2C_DUALADDRESS_DISABLED; + init->GeneralCallMode = I2C_GENERALCALL_DISABLED; + init->NoStretchMode = I2C_NOSTRETCH_DISABLE; + init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS; + init->OwnAddress2 = 0; // unused + if (freq != -1) { + i2c_set_baudrate(init, MIN(freq, MICROPY_HW_I2C_BAUDRATE_MAX)); + } + + *self->use_dma = false; + + // init the I2C bus + i2c_deinit(self->i2c); + pyb_i2c_init(self->i2c); +} + +STATIC void i2c_reset_after_error(I2C_HandleTypeDef *i2c) { + // wait for bus-busy flag to be cleared, with a timeout + for (int timeout = 50; timeout > 0; --timeout) { + if (!__HAL_I2C_GET_FLAG(i2c, I2C_FLAG_BUSY)) { + // stop bit was generated and bus is back to normal + return; + } + mp_hal_delay_ms(1); + } + // bus was/is busy, need to reset the peripheral to get it to work again + i2c_deinit(i2c); + pyb_i2c_init(i2c); +} + +void i2c_ev_irq_handler(mp_uint_t i2c_id) { + I2C_HandleTypeDef *hi2c; + + switch (i2c_id) { + #if defined(MICROPY_HW_I2C1_SCL) + case 1: + hi2c = &I2CHandle1; + break; + #endif + #if defined(MICROPY_HW_I2C2_SCL) + case 2: + hi2c = &I2CHandle2; + break; + #endif + #if defined(MICROPY_HW_I2C3_SCL) + case 3: + hi2c = &I2CHandle3; + break; + #endif + #if defined(MICROPY_HW_I2C4_SCL) + case 4: + hi2c = &I2CHandle4; + break; + #endif + default: + return; + } + + #if defined(STM32F4) + + if (hi2c->Instance->SR1 & I2C_FLAG_BTF && hi2c->State == HAL_I2C_STATE_BUSY_TX) { + if (hi2c->XferCount != 0U) { + hi2c->Instance->DR = *hi2c->pBuffPtr++; + hi2c->XferCount--; + } else { + __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR); + if (hi2c->XferOptions != I2C_FIRST_FRAME) { + hi2c->Instance->CR1 |= I2C_CR1_STOP; + } + hi2c->Mode = HAL_I2C_MODE_NONE; + hi2c->State = HAL_I2C_STATE_READY; + } + } + + #else + + // if not an F4 MCU, use the HAL's IRQ handler + HAL_I2C_EV_IRQHandler(hi2c); + + #endif +} + +void i2c_er_irq_handler(mp_uint_t i2c_id) { + I2C_HandleTypeDef *hi2c; + + switch (i2c_id) { + #if defined(MICROPY_HW_I2C1_SCL) + case 1: + hi2c = &I2CHandle1; + break; + #endif + #if defined(MICROPY_HW_I2C2_SCL) + case 2: + hi2c = &I2CHandle2; + break; + #endif + #if defined(MICROPY_HW_I2C3_SCL) + case 3: + hi2c = &I2CHandle3; + break; + #endif + #if defined(MICROPY_HW_I2C4_SCL) + case 4: + hi2c = &I2CHandle4; + break; + #endif + default: + return; + } + + #if defined(STM32F4) + + uint32_t sr1 = hi2c->Instance->SR1; + + // I2C Bus error + if (sr1 & I2C_FLAG_BERR) { + hi2c->ErrorCode |= HAL_I2C_ERROR_BERR; + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR); + } + + // I2C Arbitration Loss error + if (sr1 & I2C_FLAG_ARLO) { + hi2c->ErrorCode |= HAL_I2C_ERROR_ARLO; + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO); + } + + // I2C Acknowledge failure + if (sr1 & I2C_FLAG_AF) { + hi2c->ErrorCode |= HAL_I2C_ERROR_AF; + SET_BIT(hi2c->Instance->CR1,I2C_CR1_STOP); + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); + } + + // I2C Over-Run/Under-Run + if (sr1 & I2C_FLAG_OVR) { + hi2c->ErrorCode |= HAL_I2C_ERROR_OVR; + __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR); + } + + #else + + // if not an F4 MCU, use the HAL's IRQ handler + HAL_I2C_ER_IRQHandler(hi2c); + + #endif +} + +STATIC HAL_StatusTypeDef i2c_wait_dma_finished(I2C_HandleTypeDef *i2c, uint32_t timeout) { + // Note: we can't use WFI to idle in this loop because the DMA completion + // interrupt may occur before the WFI. Hence we miss it and have to wait + // until the next sys-tick (up to 1ms). + uint32_t start = HAL_GetTick(); + while (HAL_I2C_GetState(i2c) != HAL_I2C_STATE_READY) { + if (HAL_GetTick() - start >= timeout) { + return HAL_TIMEOUT; + } + } + return HAL_OK; +} + +/******************************************************************************/ +/* MicroPython bindings */ + +static inline bool in_master_mode(pyb_i2c_obj_t *self) { return self->i2c->Init.OwnAddress1 == PYB_I2C_MASTER_ADDRESS; } + +STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_i2c_obj_t *self = self_in; + + uint i2c_num = 0; + if (0) { } + #if defined(MICROPY_HW_I2C1_SCL) + else if (self->i2c->Instance == I2C1) { i2c_num = 1; } + #endif + #if defined(MICROPY_HW_I2C2_SCL) + else if (self->i2c->Instance == I2C2) { i2c_num = 2; } + #endif + #if defined(MICROPY_HW_I2C3_SCL) + else if (self->i2c->Instance == I2C3) { i2c_num = 3; } + #endif + #if defined(MICROPY_HW_I2C4_SCL) + else if (self->i2c->Instance == I2C4) { i2c_num = 4; } + #endif + + if (self->i2c->State == HAL_I2C_STATE_RESET) { + mp_printf(print, "I2C(%u)", i2c_num); + } else { + if (in_master_mode(self)) { + mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, pyb_i2c_get_baudrate(self->i2c)); + } else { + mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f); + } + } +} + +/// \method init(mode, *, addr=0x12, baudrate=400000, gencall=False) +/// +/// Initialise the I2C bus with the given parameters: +/// +/// - `mode` must be either `I2C.MASTER` or `I2C.SLAVE` +/// - `addr` is the 7-bit address (only sensible for a slave) +/// - `baudrate` is the SCL clock rate (only sensible for a master) +/// - `gencall` is whether to support general call mode +STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_INT, {.u_int = PYB_I2C_MASTER} }, + { MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x12} }, + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_HW_I2C_BAUDRATE_DEFAULT} }, + { MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_dma, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + // 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 the I2C configuration values + I2C_InitTypeDef *init = &self->i2c->Init; + + if (args[0].u_int == PYB_I2C_MASTER) { + // use a special address to indicate we are a master + init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS; + } else { + init->OwnAddress1 = (args[1].u_int << 1) & 0xfe; + } + + i2c_set_baudrate(init, MIN(args[2].u_int, MICROPY_HW_I2C_BAUDRATE_MAX)); + init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; + init->DualAddressMode = I2C_DUALADDRESS_DISABLED; + init->GeneralCallMode = args[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED; + init->OwnAddress2 = 0; // unused + init->NoStretchMode = I2C_NOSTRETCH_DISABLE; + + *self->use_dma = args[4].u_bool; + + // init the I2C bus + i2c_deinit(self->i2c); + pyb_i2c_init(self->i2c); + + return mp_const_none; +} + +/// \classmethod \constructor(bus, ...) +/// +/// Construct an I2C object on the given bus. `bus` can be 1 or 2. +/// With no additional parameters, the I2C object is created but not +/// initialised (it has the settings from the last initialisation of +/// the bus, if any). If extra arguments are given, the bus is initialised. +/// See `init` for parameters of initialisation. +/// +/// The physical pins of the I2C busses are: +/// +/// - `I2C(1)` is on the X position: `(SCL, SDA) = (X9, X10) = (PB6, PB7)` +/// - `I2C(2)` is on the Y position: `(SCL, SDA) = (Y9, Y10) = (PB10, PB11)` +STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // work out i2c bus + int i2c_id = 0; + if (MP_OBJ_IS_STR(args[0])) { + const char *port = mp_obj_str_get_str(args[0]); + if (0) { + #ifdef MICROPY_HW_I2C1_NAME + } else if (strcmp(port, MICROPY_HW_I2C1_NAME) == 0) { + i2c_id = 1; + #endif + #ifdef MICROPY_HW_I2C2_NAME + } else if (strcmp(port, MICROPY_HW_I2C2_NAME) == 0) { + i2c_id = 2; + #endif + #ifdef MICROPY_HW_I2C3_NAME + } else if (strcmp(port, MICROPY_HW_I2C3_NAME) == 0) { + i2c_id = 3; + #endif + #ifdef MICROPY_HW_I2C4_NAME + } else if (strcmp(port, MICROPY_HW_I2C4_NAME) == 0) { + i2c_id = 4; + #endif + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C(%s) doesn't exist", port)); + } + } else { + i2c_id = mp_obj_get_int(args[0]); + if (i2c_id < 1 || i2c_id > MP_ARRAY_SIZE(pyb_i2c_obj) + || pyb_i2c_obj[i2c_id - 1].i2c == NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "I2C(%d) doesn't exist", i2c_id)); + } + } + + // get I2C object + const pyb_i2c_obj_t *i2c_obj = &pyb_i2c_obj[i2c_id - 1]; + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_i2c_init_helper(i2c_obj, n_args - 1, args + 1, &kw_args); + } + + return (mp_obj_t)i2c_obj; +} + +STATIC mp_obj_t pyb_i2c_init_(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_i2c_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init_); + +/// \method deinit() +/// Turn off the I2C bus. +STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) { + pyb_i2c_obj_t *self = self_in; + i2c_deinit(self->i2c); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit); + +/// \method is_ready(addr) +/// Check if an I2C device responds to the given address. Only valid when in master mode. +STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) { + pyb_i2c_obj_t *self = self_in; + + if (!in_master_mode(self)) { + mp_raise_TypeError("I2C must be a master"); + } + + mp_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1; + + for (int i = 0; i < 10; i++) { + HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, i2c_addr, 10, 200); + if (status == HAL_OK) { + return mp_const_true; + } + } + + return mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready); + +/// \method scan() +/// Scan all I2C addresses from 0x08 to 0x77 and return a list of those that respond. +/// Only valid when in master mode. +STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) { + pyb_i2c_obj_t *self = self_in; + + if (!in_master_mode(self)) { + mp_raise_TypeError("I2C must be a master"); + } + + mp_obj_t list = mp_obj_new_list(0, NULL); + + for (uint addr = 0x08; addr <= 0x77; addr++) { + HAL_StatusTypeDef status = HAL_I2C_IsDeviceReady(self->i2c, addr << 1, 1, 200); + if (status == HAL_OK) { + mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); + } + } + + return list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan); + +/// \method send(send, addr=0x00, timeout=5000) +/// Send data on the bus: +/// +/// - `send` is the data to send (an integer to send, or a buffer object) +/// - `addr` is the address to send to (only required in master mode) +/// - `timeout` is the timeout in milliseconds to wait for the send +/// +/// Return value: `None`. +STATIC mp_obj_t pyb_i2c_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + }; + + // parse args + pyb_i2c_obj_t *self = 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 the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); + + // if option is set and IRQs are enabled then we can use DMA + bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; + + DMA_HandleTypeDef tx_dma; + if (use_dma) { + dma_init(&tx_dma, self->tx_dma_descr, self->i2c); + self->i2c->hdmatx = &tx_dma; + self->i2c->hdmarx = NULL; + } + + // send the data + HAL_StatusTypeDef status; + if (in_master_mode(self)) { + if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) { + if (use_dma) { + dma_deinit(self->tx_dma_descr); + } + mp_raise_TypeError("addr argument required"); + } + mp_uint_t i2c_addr = args[1].u_int << 1; + if (!use_dma) { + status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, args[2].u_int); + } else { + MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len); + status = HAL_I2C_Master_Transmit_DMA(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len); + } + } else { + if (!use_dma) { + status = HAL_I2C_Slave_Transmit(self->i2c, bufinfo.buf, bufinfo.len, args[2].u_int); + } else { + MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len); + status = HAL_I2C_Slave_Transmit_DMA(self->i2c, bufinfo.buf, bufinfo.len); + } + } + + // if we used DMA, wait for it to finish + if (use_dma) { + if (status == HAL_OK) { + status = i2c_wait_dma_finished(self->i2c, args[2].u_int); + } + dma_deinit(self->tx_dma_descr); + } + + if (status != HAL_OK) { + i2c_reset_after_error(self->i2c); + mp_hal_raise(status); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send); + +/// \method recv(recv, addr=0x00, timeout=5000) +/// +/// Receive data on the bus: +/// +/// - `recv` can be an integer, which is the number of bytes to receive, +/// or a mutable buffer, which will be filled with received bytes +/// - `addr` is the address to receive from (only required in master mode) +/// - `timeout` is the timeout in milliseconds to wait for the receive +/// +/// Return value: if `recv` is an integer then a new buffer of the bytes received, +/// otherwise the same buffer that was passed in to `recv`. +STATIC mp_obj_t pyb_i2c_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + }; + + // parse args + pyb_i2c_obj_t *self = 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 the buffer to receive into + vstr_t vstr; + mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); + + // if option is set and IRQs are enabled then we can use DMA + bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; + + DMA_HandleTypeDef rx_dma; + if (use_dma) { + dma_init(&rx_dma, self->rx_dma_descr, self->i2c); + self->i2c->hdmatx = NULL; + self->i2c->hdmarx = &rx_dma; + } + + // receive the data + HAL_StatusTypeDef status; + if (in_master_mode(self)) { + if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) { + mp_raise_TypeError("addr argument required"); + } + mp_uint_t i2c_addr = args[1].u_int << 1; + if (!use_dma) { + status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len, args[2].u_int); + } else { + MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len); + status = HAL_I2C_Master_Receive_DMA(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len); + } + } else { + if (!use_dma) { + status = HAL_I2C_Slave_Receive(self->i2c, (uint8_t*)vstr.buf, vstr.len, args[2].u_int); + } else { + MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len); + status = HAL_I2C_Slave_Receive_DMA(self->i2c, (uint8_t*)vstr.buf, vstr.len); + } + } + + // if we used DMA, wait for it to finish + if (use_dma) { + if (status == HAL_OK) { + status = i2c_wait_dma_finished(self->i2c, args[2].u_int); + } + dma_deinit(self->rx_dma_descr); + } + + if (status != HAL_OK) { + i2c_reset_after_error(self->i2c); + mp_hal_raise(status); + } + + // return the received data + if (o_ret != MP_OBJ_NULL) { + return o_ret; + } else { + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv); + +/// \method mem_read(data, addr, memaddr, timeout=5000, addr_size=8) +/// +/// Read from the memory of an I2C device: +/// +/// - `data` can be an integer or a buffer to read into +/// - `addr` is the I2C device address +/// - `memaddr` is the memory location within the I2C device +/// - `timeout` is the timeout in milliseconds to wait for the read +/// - `addr_size` selects width of memaddr: 8 or 16 bits +/// +/// Returns the read data. +/// This is only valid in master mode. +STATIC const mp_arg_t pyb_i2c_mem_read_allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, + { MP_QSTR_addr_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, +}; + +STATIC mp_obj_t pyb_i2c_mem_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + pyb_i2c_obj_t *self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args); + + if (!in_master_mode(self)) { + mp_raise_TypeError("I2C must be a master"); + } + + // get the buffer to read into + vstr_t vstr; + mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); + + // get the addresses + mp_uint_t i2c_addr = args[1].u_int << 1; + mp_uint_t mem_addr = args[2].u_int; + // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width + mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT; + if (args[4].u_int != 8) { + mem_addr_size = I2C_MEMADD_SIZE_16BIT; + } + + // if option is set and IRQs are enabled then we can use DMA + bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; + + HAL_StatusTypeDef status; + if (!use_dma) { + status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len, args[3].u_int); + } else { + DMA_HandleTypeDef rx_dma; + dma_init(&rx_dma, self->rx_dma_descr, self->i2c); + self->i2c->hdmatx = NULL; + self->i2c->hdmarx = &rx_dma; + MP_HAL_CLEANINVALIDATE_DCACHE(vstr.buf, vstr.len); + status = HAL_I2C_Mem_Read_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len); + if (status == HAL_OK) { + status = i2c_wait_dma_finished(self->i2c, args[3].u_int); + } + dma_deinit(self->rx_dma_descr); + } + + if (status != HAL_OK) { + i2c_reset_after_error(self->i2c); + mp_hal_raise(status); + } + + // return the read data + if (o_ret != MP_OBJ_NULL) { + return o_ret; + } else { + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read); + +/// \method mem_write(data, addr, memaddr, timeout=5000, addr_size=8) +/// +/// Write to the memory of an I2C device: +/// +/// - `data` can be an integer or a buffer to write from +/// - `addr` is the I2C device address +/// - `memaddr` is the memory location within the I2C device +/// - `timeout` is the timeout in milliseconds to wait for the write +/// - `addr_size` selects width of memaddr: 8 or 16 bits +/// +/// Returns `None`. +/// This is only valid in master mode. +STATIC mp_obj_t pyb_i2c_mem_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args (same as mem_read) + pyb_i2c_obj_t *self = pos_args[0]; + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(pyb_i2c_mem_read_allowed_args), pyb_i2c_mem_read_allowed_args, args); + + if (!in_master_mode(self)) { + mp_raise_TypeError("I2C must be a master"); + } + + // get the buffer to write from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); + + // get the addresses + mp_uint_t i2c_addr = args[1].u_int << 1; + mp_uint_t mem_addr = args[2].u_int; + // determine width of mem_addr; default is 8 bits, entering any other value gives 16 bit width + mp_uint_t mem_addr_size = I2C_MEMADD_SIZE_8BIT; + if (args[4].u_int != 8) { + mem_addr_size = I2C_MEMADD_SIZE_16BIT; + } + + // if option is set and IRQs are enabled then we can use DMA + bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED; + + HAL_StatusTypeDef status; + if (!use_dma) { + status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len, args[3].u_int); + } else { + DMA_HandleTypeDef tx_dma; + dma_init(&tx_dma, self->tx_dma_descr, self->i2c); + self->i2c->hdmatx = &tx_dma; + self->i2c->hdmarx = NULL; + MP_HAL_CLEAN_DCACHE(bufinfo.buf, bufinfo.len); + status = HAL_I2C_Mem_Write_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len); + if (status == HAL_OK) { + status = i2c_wait_dma_finished(self->i2c, args[3].u_int); + } + dma_deinit(self->tx_dma_descr); + } + + if (status != HAL_OK) { + i2c_reset_after_error(self->i2c); + mp_hal_raise(status); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_write_obj, 1, pyb_i2c_mem_write); + +STATIC const mp_rom_map_elem_t pyb_i2c_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_i2c_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_i2c_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_ready), MP_ROM_PTR(&pyb_i2c_is_ready_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&pyb_i2c_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_i2c_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_i2c_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem_read), MP_ROM_PTR(&pyb_i2c_mem_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem_write), MP_ROM_PTR(&pyb_i2c_mem_write_obj) }, + + // class constants + /// \constant MASTER - for initialising the bus to master mode + /// \constant SLAVE - for initialising the bus to slave mode + { MP_ROM_QSTR(MP_QSTR_MASTER), MP_ROM_INT(PYB_I2C_MASTER) }, + { MP_ROM_QSTR(MP_QSTR_SLAVE), MP_ROM_INT(PYB_I2C_SLAVE) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table); + +const mp_obj_type_t pyb_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .print = pyb_i2c_print, + .make_new = pyb_i2c_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_i2c_locals_dict, +}; + +#endif // MICROPY_PY_PYB_LEGACY && MICROPY_HW_ENABLE_HW_I2C diff --git a/ports/stm32/pybthread.h b/ports/stm32/pybthread.h index f628f934bc..42300508c9 100644 --- a/ports/stm32/pybthread.h +++ b/ports/stm32/pybthread.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_PYBTHREAD_H -#define MICROPY_INCLUDED_STMHAL_PYBTHREAD_H +#ifndef MICROPY_INCLUDED_STM32_PYBTHREAD_H +#define MICROPY_INCLUDED_STM32_PYBTHREAD_H typedef struct _pyb_thread_t { void *sp; @@ -74,4 +74,4 @@ void pyb_mutex_init(pyb_mutex_t *m); int pyb_mutex_lock(pyb_mutex_t *m, int wait); void pyb_mutex_unlock(pyb_mutex_t *m); -#endif // MICROPY_INCLUDED_STMHAL_PYBTHREAD_H +#endif // MICROPY_INCLUDED_STM32_PYBTHREAD_H diff --git a/ports/stm32/qspi.c b/ports/stm32/qspi.c new file mode 100644 index 0000000000..a7cbbde014 --- /dev/null +++ b/ports/stm32/qspi.c @@ -0,0 +1,282 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "qspi.h" + +#if defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) + +void qspi_init(void) { + // Configure pins + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_CS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 10); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_SCK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + mp_hal_pin_config(MICROPY_HW_QSPIFLASH_IO3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, 9); + + // Bring up the QSPI peripheral + + __HAL_RCC_QSPI_CLK_ENABLE(); + + QUADSPI->CR = + 2 << QUADSPI_CR_PRESCALER_Pos // F_CLK = F_AHB/3 (72MHz when CPU is 216MHz) + | 3 << QUADSPI_CR_FTHRES_Pos // 4 bytes must be available to read/write + #if defined(QUADSPI_CR_FSEL_Pos) + | 0 << QUADSPI_CR_FSEL_Pos // FLASH 1 selected + #endif + #if defined(QUADSPI_CR_DFM_Pos) + | 0 << QUADSPI_CR_DFM_Pos // dual-flash mode disabled + #endif + | 0 << QUADSPI_CR_SSHIFT_Pos // no sample shift + | 1 << QUADSPI_CR_TCEN_Pos // timeout counter enabled + | 1 << QUADSPI_CR_EN_Pos // enable the peripheral + ; + + QUADSPI->DCR = + (MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2 - 3 - 1) << QUADSPI_DCR_FSIZE_Pos + | 1 << QUADSPI_DCR_CSHT_Pos // nCS stays high for 2 cycles + | 0 << QUADSPI_DCR_CKMODE_Pos // CLK idles at low state + ; +} + +void qspi_memory_map(void) { + // Enable memory-mapped mode + + QUADSPI->ABR = 0; // disable continuous read mode + QUADSPI->LPTR = 100; // to tune + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 3 << QUADSPI_CCR_FMODE_Pos // memory-mapped mode + | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines + | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles + | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte + | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | 0xeb << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode + ; +} + +STATIC int qspi_ioctl(void *self_in, uint32_t cmd) { + (void)self_in; + switch (cmd) { + case MP_QSPI_IOCTL_INIT: + qspi_init(); + break; + case MP_QSPI_IOCTL_BUS_RELEASE: + // Switch to memory-map mode when bus is idle + qspi_memory_map(); + break; + } + return 0; // success +} + +STATIC void qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + if (len == 0) { + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 0 << QUADSPI_CCR_DMODE_Pos // no data + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + } else { + QUADSPI->DLR = len - 1; + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + + // This assumes len==2 + *(uint16_t*)&QUADSPI->DR = data; + } + + // Wait for write to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +STATIC void qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + if (len == 0) { + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 0 << QUADSPI_CCR_DMODE_Pos // no data + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + + QUADSPI->AR = addr; + } else { + QUADSPI->DLR = len - 1; + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 0 << QUADSPI_CCR_FMODE_Pos // indirect write mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 1 << QUADSPI_CCR_ADMODE_Pos // address on 1 line + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // write opcode + ; + + QUADSPI->AR = addr; + + // Write out the data 1 byte at a time + while (len) { + while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + } + *(volatile uint8_t*)&QUADSPI->DR = *src++; + --len; + } + } + + // Wait for write to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +STATIC uint32_t qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + QUADSPI->DLR = len - 1; // number of bytes to read + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // read opcode + ; + + // Wait for read to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + // Read result + return QUADSPI->DR; +} + +STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { + (void)self_in; + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + QUADSPI->DLR = len - 1; // number of bytes to read + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode + | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines + | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles + | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte + | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode + ; + + QUADSPI->ABR = 0; // alternate byte: disable continuous read mode + QUADSPI->AR = addr; // addres to read from + + // Read in the data 4 bytes at a time if dest is aligned + if (((uintptr_t)dest & 3) == 0) { + while (len >= 4) { + while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + } + *(uint32_t*)dest = QUADSPI->DR; + dest += 4; + len -= 4; + } + } + + // Read in remaining data 1 byte at a time + while (len) { + while (!((QUADSPI->SR >> QUADSPI_SR_FLEVEL_Pos) & 0x3f)) { + } + *dest++ = *(volatile uint8_t*)&QUADSPI->DR; + --len; + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +const mp_qspi_proto_t qspi_proto = { + .ioctl = qspi_ioctl, + .write_cmd_data = qspi_write_cmd_data, + .write_cmd_addr_data = qspi_write_cmd_addr_data, + .read_cmd = qspi_read_cmd, + .read_cmd_qaddr_qdata = qspi_read_cmd_qaddr_qdata, +}; + +#endif // defined(MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) diff --git a/ports/stm32/qspi.h b/ports/stm32/qspi.h new file mode 100644 index 0000000000..c774b12582 --- /dev/null +++ b/ports/stm32/qspi.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32_QSPI_H +#define MICROPY_INCLUDED_STM32_QSPI_H + +#include "drivers/bus/qspi.h" + +extern const mp_qspi_proto_t qspi_proto; + +void qspi_init(void); +void qspi_memory_map(void); + +#endif // MICROPY_INCLUDED_STM32_QSPI_H diff --git a/ports/stm32/resethandler.s b/ports/stm32/resethandler.s new file mode 100644 index 0000000000..7f0973346e --- /dev/null +++ b/ports/stm32/resethandler.s @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m4 + .thumb + + .section .text.Reset_Handler + .global Reset_Handler + .type Reset_Handler, %function + +Reset_Handler: + /* Save the first argument to pass through to stm32_main */ + mov r4, r0 + + /* Load the stack pointer */ + ldr sp, =_estack + + /* Initialise the data section */ + ldr r1, =_sidata + ldr r2, =_sdata + ldr r3, =_edata + b .data_copy_entry +.data_copy_loop: + ldr r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */ + str r0, [r2], #4 +.data_copy_entry: + cmp r2, r3 + bcc .data_copy_loop + + /* Zero out the BSS section */ + movs r0, #0 + ldr r1, =_sbss + ldr r2, =_ebss + b .bss_zero_entry +.bss_zero_loop: + str r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */ +.bss_zero_entry: + cmp r1, r2 + bcc .bss_zero_loop + + /* Initialise the system and jump to the main code */ + bl SystemInit + mov r0, r4 + b stm32_main + + .size Reset_Handler, .-Reset_Handler diff --git a/ports/stm32/resethandler_m0.s b/ports/stm32/resethandler_m0.s new file mode 100644 index 0000000000..bb88e8daef --- /dev/null +++ b/ports/stm32/resethandler_m0.s @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m0 + .thumb + + .section .text.Reset_Handler + .global Reset_Handler + .type Reset_Handler, %function + +Reset_Handler: + /* Save the first argument to pass through to stm32_main */ + mov r4, r0 + + /* Load the stack pointer */ + ldr r0, =_estack + mov sp, r0 + + /* Initialise the data section */ + ldr r1, =_sidata + ldr r2, =_sdata + ldr r3, =_edata + b .data_copy_entry +.data_copy_loop: + ldr r0, [r1] + adds r1, #4 + str r0, [r2] + adds r2, #4 +.data_copy_entry: + cmp r2, r3 + bcc .data_copy_loop + + /* Zero out the BSS section */ + movs r0, #0 + ldr r1, =_sbss + ldr r2, =_ebss + b .bss_zero_entry +.bss_zero_loop: + str r0, [r1] + adds r1, #4 +.bss_zero_entry: + cmp r1, r2 + bcc .bss_zero_loop + + /* Initialise the system and jump to the main code */ + bl SystemInit + mov r0, r4 + bl stm32_main + + .size Reset_Handler, .-Reset_Handler diff --git a/ports/stm32/rng.c b/ports/stm32/rng.c index c0c5e9aeb5..b23941998a 100644 --- a/ports/stm32/rng.c +++ b/ports/stm32/rng.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,44 +24,66 @@ * THE SOFTWARE. */ -#include - -#include "py/obj.h" #include "rng.h" #if MICROPY_HW_ENABLE_RNG -/// \moduleref pyb +#define RNG_TIMEOUT_MS (10) -STATIC RNG_HandleTypeDef RNGHandle = {.Instance = NULL}; +uint32_t rng_get(void) { + // Enable the RNG peripheral if it's not already enabled + if (!(RNG->CR & RNG_CR_RNGEN)) { + #if defined(STM32H7) + // Set RNG Clock source + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVQ); + __HAL_RCC_RNG_CONFIG(RCC_RNGCLKSOURCE_PLL); + #endif + __HAL_RCC_RNG_CLK_ENABLE(); + RNG->CR |= RNG_CR_RNGEN; + } -void rng_init0(void) { - // reset the RNG handle - memset(&RNGHandle, 0, sizeof(RNG_HandleTypeDef)); - RNGHandle.Instance = RNG; + // Wait for a new random number to be ready, takes on the order of 10us + uint32_t start = HAL_GetTick(); + while (!(RNG->SR & RNG_SR_DRDY)) { + if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) { + return 0; + } + } + + // Get and return the new random number + return RNG->DR; } -void rng_init(void) { - __RNG_CLK_ENABLE(); - HAL_RNG_Init(&RNGHandle); +// Return a 30-bit hardware generated random number. +STATIC mp_obj_t pyb_rng_get(void) { + return mp_obj_new_int(rng_get() >> 2); +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get); + +#else // MICROPY_HW_ENABLE_RNG + +// For MCUs that don't have an RNG we still need to provide a rng_get() function, +// eg for lwIP. A pseudo-RNG is not really ideal but we go with it for now. We +// don't want to use urandom's pRNG because then the user won't see a reproducible +// random stream. + +// Yasmarang random number generator by Ilya Levin +// http://www.literatecode.com/yasmarang +STATIC uint32_t pyb_rng_yasmarang(void) { + static uint32_t pad = 0xeda4baba, n = 69, d = 233; + static uint8_t dat = 0; + + pad += dat + d * n; + pad = (pad << 3) + (pad >> 29); + n = pad | 2; + d ^= (pad << 31) + (pad >> 1); + dat ^= (char)pad ^ (d >> 8) ^ 1; + + return pad ^ (d << 5) ^ (pad >> 18) ^ (dat << 1); } uint32_t rng_get(void) { - if (RNGHandle.State == HAL_RNG_STATE_RESET) { - rng_init(); - } - return HAL_RNG_GetRandomNumber(&RNGHandle); + return pyb_rng_yasmarang(); } -/// \function rng() -/// Return a 30-bit hardware generated random number. -STATIC mp_obj_t pyb_rng_get(void) { - if (RNGHandle.State == HAL_RNG_STATE_RESET) { - rng_init(); - } - return mp_obj_new_int(HAL_RNG_GetRandomNumber(&RNGHandle) >> 2); -} - -MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get); - #endif // MICROPY_HW_ENABLE_RNG diff --git a/ports/stm32/rng.h b/ports/stm32/rng.h index 43e49fe72e..ed9cc80f2b 100644 --- a/ports/stm32/rng.h +++ b/ports/stm32/rng.h @@ -23,12 +23,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_RNG_H -#define MICROPY_INCLUDED_STMHAL_RNG_H +#ifndef MICROPY_INCLUDED_STM32_RNG_H +#define MICROPY_INCLUDED_STM32_RNG_H + +#include "py/obj.h" -void rng_init0(void); uint32_t rng_get(void); MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj); -#endif // MICROPY_INCLUDED_STMHAL_RNG_H +#endif // MICROPY_INCLUDED_STM32_RNG_H diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 73272d3631..c51dfab119 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -132,13 +132,14 @@ void rtc_init_start(bool force_init) { // provide some status information rtc_info |= 0x40000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; return; - } else if (((RCC->BDCR & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL_1) && ((RCC->CSR & 3) == 3)) { - // LSI configured & enabled & ready --> no need to (re-)init RTC + } else if ((RCC->BDCR & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL_1) { + // LSI configured as the RTC clock source --> no need to (re-)init RTC // remove Backup Domain write protection HAL_PWR_EnableBkUpAccess(); // Clear source Reset Flag __HAL_RCC_CLEAR_RESET_FLAGS(); - RCC->CSR |= 1; + // Turn the LSI on (it may need this even if the RTC is running) + RCC->CSR |= RCC_CSR_LSION; // provide some status information rtc_info |= 0x80000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; return; @@ -162,7 +163,7 @@ void rtc_init_finalise() { return; } - rtc_info = 0x20000000 | (rtc_use_lse << 28); + rtc_info = 0x20000000; if (PYB_RTC_Init(&RTCHandle) != HAL_OK) { if (rtc_use_lse) { // fall back to LSI... @@ -182,12 +183,15 @@ void rtc_init_finalise() { } } + // record if LSE or LSI is used + rtc_info |= (rtc_use_lse << 28); + // record how long it took for the RTC to start up rtc_info |= (HAL_GetTick() - rtc_startup_tick) & 0xffff; // fresh reset; configure RTC Calendar RTC_CalendarConfig(); - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) if(__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST) != RESET) { #else if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET) { @@ -219,12 +223,16 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc /*------------------------------ LSE Configuration -------------------------*/ if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) { + #if !defined(STM32H7) // Enable Power Clock - __PWR_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + #endif + + // Enable access to the backup domain HAL_PWR_EnableBkUpAccess(); uint32_t tickstart = HAL_GetTick(); - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) + #if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) //__HAL_RCC_PWR_CLK_ENABLE(); // Enable write access to Backup domain //PWR->CR1 |= PWR_CR1_DBP; @@ -239,7 +247,7 @@ STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruc //PWR->CR |= PWR_CR_DBP; // Wait for Backup domain Write protection disable while ((PWR->CR & PWR_CR_DBP) == RESET) { - if (HAL_GetTick() - tickstart > DBP_TIMEOUT_VALUE) { + if (HAL_GetTick() - tickstart > RCC_DBP_TIMEOUT_VALUE) { return HAL_TIMEOUT; } } @@ -294,10 +302,10 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) { // Exit Initialization mode hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT; - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) || defined(STM32H7) hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE; hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); - #elif defined(MCU_SERIES_F7) + #elif defined(STM32F7) hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMTYPE; hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); #else @@ -331,7 +339,11 @@ STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) { RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (rtc_use_lse) { + #if MICROPY_HW_RTC_USE_BYPASS + RCC_OscInitStruct.LSEState = RCC_LSE_BYPASS; + #else RCC_OscInitStruct.LSEState = RCC_LSE_ON; + #endif RCC_OscInitStruct.LSIState = RCC_LSI_OFF; } else { RCC_OscInitStruct.LSEState = RCC_LSE_OFF; @@ -391,7 +403,7 @@ STATIC void RTC_CalendarConfig(void) { date.Date = 1; date.WeekDay = RTC_WEEKDAY_THURSDAY; - if(HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN) != HAL_OK) { + if(HAL_RTC_SetDate(&RTCHandle, &date, RTC_FORMAT_BIN) != HAL_OK) { // init error return; } @@ -405,7 +417,7 @@ STATIC void RTC_CalendarConfig(void) { time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; time.StoreOperation = RTC_STOREOPERATION_RESET; - if (HAL_RTC_SetTime(&RTCHandle, &time, FORMAT_BIN) != HAL_OK) { + if (HAL_RTC_SetTime(&RTCHandle, &time, RTC_FORMAT_BIN) != HAL_OK) { // init error return; } @@ -488,8 +500,8 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { // note: need to call get time then get date to correctly access the registers RTC_DateTypeDef date; RTC_TimeTypeDef time; - HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); - HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_GetTime(&RTCHandle, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&RTCHandle, &date, RTC_FORMAT_BIN); mp_obj_t tuple[8] = { mp_obj_new_int(2000 + date.Year), mp_obj_new_int(date.Month), @@ -511,23 +523,26 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { date.Month = mp_obj_get_int(items[1]); date.Date = mp_obj_get_int(items[2]); date.WeekDay = mp_obj_get_int(items[3]); - HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_SetDate(&RTCHandle, &date, RTC_FORMAT_BIN); RTC_TimeTypeDef time; time.Hours = mp_obj_get_int(items[4]); time.Minutes = mp_obj_get_int(items[5]); time.Seconds = mp_obj_get_int(items[6]); - time.SubSeconds = rtc_us_to_subsec(mp_obj_get_int(items[7])); time.TimeFormat = RTC_HOURFORMAT12_AM; time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; time.StoreOperation = RTC_STOREOPERATION_SET; - HAL_RTC_SetTime(&RTCHandle, &time, FORMAT_BIN); + HAL_RTC_SetTime(&RTCHandle, &time, RTC_FORMAT_BIN); return mp_const_none; } } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime); +#if defined(STM32F0) +#define RTC_WKUP_IRQn RTC_IRQn +#endif + // wakeup(None) // wakeup(ms, callback=None) // wakeup(wucksel, wut, callback) @@ -623,9 +638,12 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { RTC->WPR = 0xff; // enable external interrupts on line 22 - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) EXTI->IMR1 |= 1 << 22; EXTI->RTSR1 |= 1 << 22; + #elif defined(STM32H7) + EXTI_D1->IMR1 |= 1 << 22; + EXTI->RTSR1 |= 1 << 22; #else EXTI->IMR |= 1 << 22; EXTI->RTSR |= 1 << 22; @@ -633,13 +651,15 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { // clear interrupt flags RTC->ISR &= ~(1 << 10); - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) EXTI->PR1 = 1 << 22; + #elif defined(STM32H7) + EXTI_D1->PR1 = 1 << 22; #else EXTI->PR = 1 << 22; #endif - HAL_NVIC_SetPriority(RTC_WKUP_IRQn, IRQ_PRI_RTC_WKUP, IRQ_SUBPRI_RTC_WKUP); + NVIC_SetPriority(RTC_WKUP_IRQn, IRQ_PRI_RTC_WKUP); HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn); //printf("wut=%d wucksel=%d\n", wut, wucksel); @@ -651,8 +671,10 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { RTC->WPR = 0xff; // disable external interrupts on line 22 - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) EXTI->IMR1 &= ~(1 << 22); + #elif defined(STM32H7) + EXTI_D1->IMR1 |= 1 << 22; #else EXTI->IMR &= ~(1 << 22); #endif diff --git a/ports/stm32/rtc.h b/ports/stm32/rtc.h index 09ab2aedff..307f8885e3 100644 --- a/ports/stm32/rtc.h +++ b/ports/stm32/rtc.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_RTC_H -#define MICROPY_INCLUDED_STMHAL_RTC_H +#ifndef MICROPY_INCLUDED_STM32_RTC_H +#define MICROPY_INCLUDED_STM32_RTC_H extern RTC_HandleTypeDef RTCHandle; extern const mp_obj_type_t pyb_rtc_type; @@ -32,4 +32,4 @@ extern const mp_obj_type_t pyb_rtc_type; void rtc_init_start(bool force_init); void rtc_init_finalise(void); -#endif // MICROPY_INCLUDED_STMHAL_RTC_H +#endif // MICROPY_INCLUDED_STM32_RTC_H diff --git a/ports/stm32/sdcard.c b/ports/stm32/sdcard.c index 484426b846..27e7a34b26 100644 --- a/ports/stm32/sdcard.c +++ b/ports/stm32/sdcard.c @@ -33,14 +33,13 @@ #include "sdcard.h" #include "pin.h" -#include "genhdr/pins.h" #include "bufhelper.h" #include "dma.h" #include "irq.h" #if MICROPY_HW_HAS_SDCARD -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) +#if defined(STM32F7) || defined(STM32H7) || defined(STM32L4) // The F7 has 2 SDMMC units but at the moment we only support using one of them in // a given build. If a boards config file defines MICROPY_HW_SDMMC2_CK then SDMMC2 @@ -81,7 +80,15 @@ #define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE #define SDIO_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_HARDWARE_FLOW_CONTROL_ENABLE +#if defined(STM32H7) +#define GPIO_AF12_SDIO GPIO_AF12_SDIO1 +#define SDIO_IRQHandler SDMMC1_IRQHandler +#define SDIO_TRANSFER_CLK_DIV SDMMC_NSpeed_CLK_DIV +#define SDIO_USE_GPDMA 0 +#else #define SDIO_TRANSFER_CLK_DIV SDMMC_TRANSFER_CLK_DIV +#define SDIO_USE_GPDMA 1 +#endif #else @@ -92,6 +99,7 @@ #define SDMMC_IRQn SDIO_IRQn #define SDMMC_TX_DMA dma_SDIO_0_TX #define SDMMC_RX_DMA dma_SDIO_0_RX +#define SDIO_USE_GPDMA 1 #endif @@ -117,7 +125,9 @@ // if an sd card is detected. This will save approx 260 bytes of RAM // when no sdcard was being used. static SD_HandleTypeDef sd_handle; +#if SDIO_USE_GPDMA static DMA_HandleTypeDef sd_rx_dma, sd_tx_dma; +#endif void sdcard_init(void) { // invalidate the sd_handle @@ -131,33 +141,39 @@ void sdcard_init(void) { // which clocks up to 25MHz maximum. #if defined(MICROPY_HW_SDMMC2_CK) // Use SDMMC2 peripheral with pins provided by the board's config - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); - mp_hal_pin_config_alt(&MICROPY_HW_SDMMC2_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); + mp_hal_pin_config_alt(MICROPY_HW_SDMMC2_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_SDMMC, 2); #else // Default SDIO/SDMMC1 config - mp_hal_pin_config(&MICROPY_HW_SDMMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); - mp_hal_pin_config(&MICROPY_HW_SDMMC_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_D0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_D1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_D2, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_D3, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_CK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); + mp_hal_pin_config(MICROPY_HW_SDMMC_CMD, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, GPIO_AF12_SDIO); #endif // configure the SD card detect pin // we do this here so we can detect if the SD card is inserted before powering it on - mp_hal_pin_config(&MICROPY_HW_SDCARD_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_SDCARD_DETECT_PULL, 0); + mp_hal_pin_config(MICROPY_HW_SDCARD_DETECT_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_SDCARD_DETECT_PULL, 0); } void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { // enable SDIO clock SDMMC_CLK_ENABLE(); + #if defined(STM32H7) + // Reset SDMMC + __HAL_RCC_SDMMC1_FORCE_RESET(); + __HAL_RCC_SDMMC1_RELEASE_RESET(); + #endif + // NVIC configuration for SDIO interrupts - HAL_NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_SDIO, IRQ_SUBPRI_SDIO); + NVIC_SetPriority(SDMMC_IRQn, IRQ_PRI_SDIO); HAL_NVIC_EnableIRQ(SDMMC_IRQn); // GPIO have already been initialised by sdcard_init @@ -169,7 +185,7 @@ void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { } bool sdcard_is_present(void) { - return HAL_GPIO_ReadPin(MICROPY_HW_SDCARD_DETECT_PIN.gpio, MICROPY_HW_SDCARD_DETECT_PIN.pin_mask) == MICROPY_HW_SDCARD_DETECT_PRESENT; + return HAL_GPIO_ReadPin(MICROPY_HW_SDCARD_DETECT_PIN->gpio, MICROPY_HW_SDCARD_DETECT_PIN->pin_mask) == MICROPY_HW_SDCARD_DETECT_PRESENT; } bool sdcard_power_on(void) { @@ -183,7 +199,9 @@ bool sdcard_power_on(void) { // SD device interface configuration sd_handle.Instance = SDIO; sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + #ifndef STM32H7 sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + #endif sd_handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE; sd_handle.Init.BusWide = SDIO_BUS_WIDE_1B; sd_handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; @@ -198,6 +216,10 @@ bool sdcard_power_on(void) { } // configure the SD bus width for wide operation + #if defined(STM32F7) + // use maximum SDMMC clock speed on F7 MCUs + sd_handle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_ENABLE; + #endif if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDIO_BUS_WIDE_4B) != HAL_OK) { HAL_SD_DeInit(&sd_handle); goto error; @@ -227,13 +249,15 @@ uint64_t sdcard_get_capacity_in_bytes(void) { return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize; } +#if !defined(MICROPY_HW_SDMMC2_CK) void SDIO_IRQHandler(void) { IRQ_ENTER(SDIO_IRQn); HAL_SD_IRQHandler(&sd_handle); IRQ_EXIT(SDIO_IRQn); } +#endif -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) void SDMMC2_IRQHandler(void) { IRQ_ENTER(SDMMC2_IRQn); HAL_SD_IRQHandler(&sd_handle); @@ -244,14 +268,23 @@ void SDMMC2_IRQHandler(void) { STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t timeout) { // Wait for HAL driver to be ready (eg for DMA to finish) uint32_t start = HAL_GetTick(); - while (sd->State == HAL_SD_STATE_BUSY) { + for (;;) { + // Do an atomic check of the state; WFI will exit even if IRQs are disabled + uint32_t irq_state = disable_irq(); + if (sd->State != HAL_SD_STATE_BUSY) { + enable_irq(irq_state); + break; + } + __WFI(); + enable_irq(irq_state); if (HAL_GetTick() - start >= timeout) { return HAL_TIMEOUT; } } + // Wait for SD card to complete the operation for (;;) { - HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd); + HAL_SD_CardStateTypedef state = HAL_SD_GetCardState(sd); if (state == HAL_SD_CARD_TRANSFER) { return HAL_OK; } @@ -261,6 +294,7 @@ STATIC HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, uint32_t tim if (HAL_GetTick() - start >= timeout) { return HAL_TIMEOUT; } + __WFI(); } return HAL_OK; } @@ -295,8 +329,10 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + #if SDIO_USE_GPDMA dma_init(&sd_rx_dma, &SDMMC_RX_DMA, &sd_handle); sd_handle.hdmarx = &sd_rx_dma; + #endif // make sure cache is flushed and invalidated so when DMA updates the RAM // from reading the peripheral the CPU then reads the new data @@ -307,8 +343,10 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo err = sdcard_wait_finished(&sd_handle, 60000); } + #if SDIO_USE_GPDMA dma_deinit(&SDMMC_RX_DMA); sd_handle.hdmarx = NULL; + #endif restore_irq_pri(basepri); } else { @@ -357,8 +395,10 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + #if SDIO_USE_GPDMA dma_init(&sd_tx_dma, &SDMMC_TX_DMA, &sd_handle); sd_handle.hdmatx = &sd_tx_dma; + #endif // make sure cache is flushed to RAM so the DMA can read the correct data MP_HAL_CLEAN_DCACHE(src, num_blocks * SDCARD_BLOCK_SIZE); @@ -367,8 +407,11 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n if (err == HAL_OK) { err = sdcard_wait_finished(&sd_handle, 60000); } + + #if SDIO_USE_GPDMA dma_deinit(&SDMMC_TX_DMA); sd_handle.hdmatx = NULL; + #endif restore_irq_pri(basepri); } else { @@ -496,7 +539,7 @@ STATIC mp_obj_t pyb_sdcard_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in return MP_OBJ_NEW_SMALL_INT(0); // success case BP_IOCTL_SEC_COUNT: - return MP_OBJ_NEW_SMALL_INT(0); // TODO + return MP_OBJ_NEW_SMALL_INT(sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE); case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(SDCARD_BLOCK_SIZE); diff --git a/ports/stm32/sdcard.h b/ports/stm32/sdcard.h index 8c698fc2f7..4afc258aa1 100644 --- a/ports/stm32/sdcard.h +++ b/ports/stm32/sdcard.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_SDCARD_H -#define MICROPY_INCLUDED_STMHAL_SDCARD_H +#ifndef MICROPY_INCLUDED_STM32_SDCARD_H +#define MICROPY_INCLUDED_STM32_SDCARD_H // this is a fixed size and should not be changed #define SDCARD_BLOCK_SIZE (512) @@ -45,4 +45,4 @@ extern const struct _mp_obj_base_t pyb_sdcard_obj; struct _fs_user_mount_t; void sdcard_init_vfs(struct _fs_user_mount_t *vfs, int part); -#endif // MICROPY_INCLUDED_STMHAL_SDCARD_H +#endif // MICROPY_INCLUDED_STM32_SDCARD_H diff --git a/ports/stm32/servo.c b/ports/stm32/servo.c index 0e54b4d0af..dc92872ebd 100644 --- a/ports/stm32/servo.c +++ b/ports/stm32/servo.c @@ -29,7 +29,6 @@ #include "py/runtime.h" #include "py/mphal.h" #include "pin.h" -#include "genhdr/pins.h" #include "timer.h" #include "servo.h" @@ -81,15 +80,15 @@ void servo_init(void) { // assign servo objects to specific pins (must be some permutation of PA0-PA3) #ifdef pyb_pin_X1 - pyb_servo_obj[0].pin = &pyb_pin_X1; - pyb_servo_obj[1].pin = &pyb_pin_X2; - pyb_servo_obj[2].pin = &pyb_pin_X3; - pyb_servo_obj[3].pin = &pyb_pin_X4; + pyb_servo_obj[0].pin = pyb_pin_X1; + pyb_servo_obj[1].pin = pyb_pin_X2; + pyb_servo_obj[2].pin = pyb_pin_X3; + pyb_servo_obj[3].pin = pyb_pin_X4; #else - pyb_servo_obj[0].pin = &pin_A0; - pyb_servo_obj[1].pin = &pin_A1; - pyb_servo_obj[2].pin = &pin_A2; - pyb_servo_obj[3].pin = &pin_A3; + pyb_servo_obj[0].pin = pin_A0; + pyb_servo_obj[1].pin = pin_A1; + pyb_servo_obj[2].pin = pin_A2; + pyb_servo_obj[3].pin = pin_A3; #endif } @@ -177,7 +176,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(pyb_pwm_set_obj, pyb_pwm_set); STATIC void pyb_servo_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_servo_obj_t *self = self_in; - mp_printf(print, "", self - &pyb_servo_obj[0] + 1, 10 * self->pulse_cur); + mp_printf(print, "", self - &pyb_servo_obj[0] + 1, 10 * self->pulse_cur); } /// \classmethod \constructor(id) diff --git a/ports/stm32/servo.h b/ports/stm32/servo.h index c602a07da5..0160568af1 100644 --- a/ports/stm32/servo.h +++ b/ports/stm32/servo.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_SERVO_H -#define MICROPY_INCLUDED_STMHAL_SERVO_H +#ifndef MICROPY_INCLUDED_STM32_SERVO_H +#define MICROPY_INCLUDED_STM32_SERVO_H void servo_init(void); void servo_timer_irq_callback(void); @@ -34,4 +34,4 @@ extern const mp_obj_type_t pyb_servo_type; MP_DECLARE_CONST_FUN_OBJ_2(pyb_servo_set_obj); MP_DECLARE_CONST_FUN_OBJ_2(pyb_pwm_set_obj); -#endif // MICROPY_INCLUDED_STMHAL_SERVO_H +#endif // MICROPY_INCLUDED_STM32_SERVO_H diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c index cfd9c2667f..e8621b0ab3 100644 --- a/ports/stm32/spi.c +++ b/ports/stm32/spi.c @@ -32,9 +32,7 @@ #include "extmod/machine_spi.h" #include "irq.h" #include "pin.h" -#include "genhdr/pins.h" #include "bufhelper.h" -#include "dma.h" #include "spi.h" /// \moduleref pyb @@ -75,13 +73,6 @@ // SPI6_TX: DMA2_Stream5.CHANNEL_1 // SPI6_RX: DMA2_Stream6.CHANNEL_1 -typedef struct _pyb_spi_obj_t { - mp_obj_base_t base; - SPI_HandleTypeDef *spi; - const dma_descr_t *tx_dma_descr; - const dma_descr_t *rx_dma_descr; -} pyb_spi_obj_t; - #if defined(MICROPY_HW_SPI1_SCK) SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL}; #endif @@ -101,63 +92,58 @@ SPI_HandleTypeDef SPIHandle5 = {.Instance = NULL}; SPI_HandleTypeDef SPIHandle6 = {.Instance = NULL}; #endif -STATIC const pyb_spi_obj_t pyb_spi_obj[] = { +const spi_t spi_obj[6] = { #if defined(MICROPY_HW_SPI1_SCK) - {{&pyb_spi_type}, &SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX}, + {&SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI2_SCK) - {{&pyb_spi_type}, &SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX}, + {&SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI3_SCK) - {{&pyb_spi_type}, &SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX}, + {&SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI4_SCK) - {{&pyb_spi_type}, &SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX}, + {&SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI5_SCK) - {{&pyb_spi_type}, &SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX}, + {&SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI6_SCK) - {{&pyb_spi_type}, &SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX}, + {&SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX}, #else - {{&pyb_spi_type}, NULL, NULL, NULL}, + {NULL, NULL, NULL}, #endif }; void spi_init0(void) { - // reset the SPI handles + // Initialise the SPI handles. + // The structs live on the BSS so all other fields will be zero after a reset. #if defined(MICROPY_HW_SPI1_SCK) - memset(&SPIHandle1, 0, sizeof(SPI_HandleTypeDef)); SPIHandle1.Instance = SPI1; #endif #if defined(MICROPY_HW_SPI2_SCK) - memset(&SPIHandle2, 0, sizeof(SPI_HandleTypeDef)); SPIHandle2.Instance = SPI2; #endif #if defined(MICROPY_HW_SPI3_SCK) - memset(&SPIHandle3, 0, sizeof(SPI_HandleTypeDef)); SPIHandle3.Instance = SPI3; #endif #if defined(MICROPY_HW_SPI4_SCK) - memset(&SPIHandle4, 0, sizeof(SPI_HandleTypeDef)); SPIHandle4.Instance = SPI4; #endif #if defined(MICROPY_HW_SPI5_SCK) - memset(&SPIHandle5, 0, sizeof(SPI_HandleTypeDef)); SPIHandle5.Instance = SPI5; #endif #if defined(MICROPY_HW_SPI6_SCK) - memset(&SPIHandle6, 0, sizeof(SPI_HandleTypeDef)); SPIHandle6.Instance = SPI6; #endif } @@ -179,14 +165,26 @@ STATIC int spi_find(mp_obj_t id) { } else if (strcmp(port, MICROPY_HW_SPI3_NAME) == 0) { return 3; #endif + #ifdef MICROPY_HW_SPI4_NAME + } else if (strcmp(port, MICROPY_HW_SPI4_NAME) == 0) { + return 4; + #endif + #ifdef MICROPY_HW_SPI5_NAME + } else if (strcmp(port, MICROPY_HW_SPI5_NAME) == 0) { + return 5; + #endif + #ifdef MICROPY_HW_SPI6_NAME + } else if (strcmp(port, MICROPY_HW_SPI6_NAME) == 0) { + return 6; + #endif } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "SPI(%s) doesn't exist", port)); } else { // given an integer id int spi_id = mp_obj_get_int(id); - if (spi_id >= 1 && spi_id <= MP_ARRAY_SIZE(pyb_spi_obj) - && pyb_spi_obj[spi_id - 1].spi != NULL) { + if (spi_id >= 1 && spi_id <= MP_ARRAY_SIZE(spi_obj) + && spi_obj[spi_id - 1].spi != NULL) { return spi_id; } nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, @@ -196,14 +194,18 @@ STATIC int spi_find(mp_obj_t id) { // sets the parameters in the SPI_InitTypeDef struct // if an argument is -1 then the corresponding parameter is not changed -STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t baudrate, +STATIC void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate, int32_t polarity, int32_t phase, int32_t bits, int32_t firstbit) { + SPI_HandleTypeDef *spi = spi_obj->spi; SPI_InitTypeDef *init = &spi->Init; if (prescale != 0xffffffff || baudrate != -1) { if (prescale == 0xffffffff) { // prescaler not given, so select one that yields at most the requested baudrate mp_uint_t spi_clock; + #if defined(STM32F0) + spi_clock = HAL_RCC_GetPCLK1Freq(); + #else if (spi->Instance == SPI2 || spi->Instance == SPI3) { // SPI2 and SPI3 are on APB1 spi_clock = HAL_RCC_GetPCLK1Freq(); @@ -211,6 +213,7 @@ STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t ba // SPI1, SPI4, SPI5 and SPI6 are on APB2 spi_clock = HAL_RCC_GetPCLK2Freq(); } + #endif prescale = spi_clock / baudrate; } if (prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; } @@ -241,83 +244,88 @@ STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t ba } // TODO allow to take a list of pins to use -void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { - const pyb_spi_obj_t *self; - const pin_obj_t *pins[4]; - pins[0] = NULL; +void spi_init(const spi_t *self, bool enable_nss_pin) { + SPI_HandleTypeDef *spi = self->spi; + const pin_obj_t *pins[4] = { NULL, NULL, NULL, NULL }; if (0) { #if defined(MICROPY_HW_SPI1_SCK) } else if (spi->Instance == SPI1) { - self = &pyb_spi_obj[0]; #if defined(MICROPY_HW_SPI1_NSS) - pins[0] = &MICROPY_HW_SPI1_NSS; + pins[0] = MICROPY_HW_SPI1_NSS; #endif - pins[1] = &MICROPY_HW_SPI1_SCK; - pins[2] = &MICROPY_HW_SPI1_MISO; - pins[3] = &MICROPY_HW_SPI1_MOSI; + pins[1] = MICROPY_HW_SPI1_SCK; + #if defined(MICROPY_HW_SPI1_MISO) + pins[2] = MICROPY_HW_SPI1_MISO; + #endif + pins[3] = MICROPY_HW_SPI1_MOSI; // enable the SPI clock - __SPI1_CLK_ENABLE(); + __HAL_RCC_SPI1_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI2_SCK) } else if (spi->Instance == SPI2) { - self = &pyb_spi_obj[1]; #if defined(MICROPY_HW_SPI2_NSS) - pins[0] = &MICROPY_HW_SPI2_NSS; + pins[0] = MICROPY_HW_SPI2_NSS; #endif - pins[1] = &MICROPY_HW_SPI2_SCK; - pins[2] = &MICROPY_HW_SPI2_MISO; - pins[3] = &MICROPY_HW_SPI2_MOSI; + pins[1] = MICROPY_HW_SPI2_SCK; + #if defined(MICROPY_HW_SPI2_MISO) + pins[2] = MICROPY_HW_SPI2_MISO; + #endif + pins[3] = MICROPY_HW_SPI2_MOSI; // enable the SPI clock - __SPI2_CLK_ENABLE(); + __HAL_RCC_SPI2_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI3_SCK) } else if (spi->Instance == SPI3) { - self = &pyb_spi_obj[2]; #if defined(MICROPY_HW_SPI3_NSS) - pins[0] = &MICROPY_HW_SPI3_NSS; + pins[0] = MICROPY_HW_SPI3_NSS; #endif - pins[1] = &MICROPY_HW_SPI3_SCK; - pins[2] = &MICROPY_HW_SPI3_MISO; - pins[3] = &MICROPY_HW_SPI3_MOSI; + pins[1] = MICROPY_HW_SPI3_SCK; + #if defined(MICROPY_HW_SPI3_MISO) + pins[2] = MICROPY_HW_SPI3_MISO; + #endif + pins[3] = MICROPY_HW_SPI3_MOSI; // enable the SPI clock - __SPI3_CLK_ENABLE(); + __HAL_RCC_SPI3_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI4_SCK) } else if (spi->Instance == SPI4) { - self = &pyb_spi_obj[3]; #if defined(MICROPY_HW_SPI4_NSS) - pins[0] = &MICROPY_HW_SPI4_NSS; + pins[0] = MICROPY_HW_SPI4_NSS; #endif - pins[1] = &MICROPY_HW_SPI4_SCK; - pins[2] = &MICROPY_HW_SPI4_MISO; - pins[3] = &MICROPY_HW_SPI4_MOSI; + pins[1] = MICROPY_HW_SPI4_SCK; + #if defined(MICROPY_HW_SPI4_MISO) + pins[2] = MICROPY_HW_SPI4_MISO; + #endif + pins[3] = MICROPY_HW_SPI4_MOSI; // enable the SPI clock - __SPI4_CLK_ENABLE(); + __HAL_RCC_SPI4_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI5_SCK) } else if (spi->Instance == SPI5) { - self = &pyb_spi_obj[4]; #if defined(MICROPY_HW_SPI5_NSS) - pins[0] = &MICROPY_HW_SPI5_NSS; + pins[0] = MICROPY_HW_SPI5_NSS; #endif - pins[1] = &MICROPY_HW_SPI5_SCK; - pins[2] = &MICROPY_HW_SPI5_MISO; - pins[3] = &MICROPY_HW_SPI5_MOSI; + pins[1] = MICROPY_HW_SPI5_SCK; + #if defined(MICROPY_HW_SPI5_MISO) + pins[2] = MICROPY_HW_SPI5_MISO; + #endif + pins[3] = MICROPY_HW_SPI5_MOSI; // enable the SPI clock - __SPI5_CLK_ENABLE(); + __HAL_RCC_SPI5_CLK_ENABLE(); #endif #if defined(MICROPY_HW_SPI6_SCK) } else if (spi->Instance == SPI6) { - self = &pyb_spi_obj[5]; #if defined(MICROPY_HW_SPI6_NSS) - pins[0] = &MICROPY_HW_SPI6_NSS; + pins[0] = MICROPY_HW_SPI6_NSS; #endif - pins[1] = &MICROPY_HW_SPI6_SCK; - pins[2] = &MICROPY_HW_SPI6_MISO; - pins[3] = &MICROPY_HW_SPI6_MOSI; + pins[1] = MICROPY_HW_SPI6_SCK; + #if defined(MICROPY_HW_SPI6_MISO) + pins[2] = MICROPY_HW_SPI6_MISO; + #endif + pins[3] = MICROPY_HW_SPI6_MOSI; // enable the SPI clock - __SPI6_CLK_ENABLE(); + __HAL_RCC_SPI6_CLK_ENABLE(); #endif } else { // SPI does not exist for this board (shouldn't get here, should be checked by caller) @@ -327,8 +335,11 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { // init the GPIO lines uint32_t mode = MP_HAL_PIN_MODE_ALT; uint32_t pull = spi->Init.CLKPolarity == SPI_POLARITY_LOW ? MP_HAL_PIN_PULL_DOWN : MP_HAL_PIN_PULL_UP; - for (uint i = (enable_nss_pin && pins[0] ? 0 : 1); i < 4; i++) { - mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_SPI, (self - &pyb_spi_obj[0]) + 1); + for (uint i = (enable_nss_pin ? 0 : 1); i < 4; i++) { + if (pins[i] == NULL) { + continue; + } + mp_hal_pin_config_alt(pins[i], mode, pull, AF_FN_SPI, (self - &spi_obj[0]) + 1); } // init the SPI device @@ -347,55 +358,61 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { dma_invalidate_channel(self->rx_dma_descr); } -void spi_deinit(SPI_HandleTypeDef *spi) { +void spi_deinit(const spi_t *spi_obj) { + SPI_HandleTypeDef *spi = spi_obj->spi; HAL_SPI_DeInit(spi); if (0) { #if defined(MICROPY_HW_SPI1_SCK) } else if (spi->Instance == SPI1) { - __SPI1_FORCE_RESET(); - __SPI1_RELEASE_RESET(); - __SPI1_CLK_DISABLE(); + __HAL_RCC_SPI1_FORCE_RESET(); + __HAL_RCC_SPI1_RELEASE_RESET(); + __HAL_RCC_SPI1_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI2_SCK) } else if (spi->Instance == SPI2) { - __SPI2_FORCE_RESET(); - __SPI2_RELEASE_RESET(); - __SPI2_CLK_DISABLE(); + __HAL_RCC_SPI2_FORCE_RESET(); + __HAL_RCC_SPI2_RELEASE_RESET(); + __HAL_RCC_SPI2_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI3_SCK) } else if (spi->Instance == SPI3) { - __SPI3_FORCE_RESET(); - __SPI3_RELEASE_RESET(); - __SPI3_CLK_DISABLE(); + __HAL_RCC_SPI3_FORCE_RESET(); + __HAL_RCC_SPI3_RELEASE_RESET(); + __HAL_RCC_SPI3_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI4_SCK) } else if (spi->Instance == SPI4) { - __SPI4_FORCE_RESET(); - __SPI4_RELEASE_RESET(); - __SPI4_CLK_DISABLE(); + __HAL_RCC_SPI4_FORCE_RESET(); + __HAL_RCC_SPI4_RELEASE_RESET(); + __HAL_RCC_SPI4_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI5_SCK) } else if (spi->Instance == SPI5) { - __SPI5_FORCE_RESET(); - __SPI5_RELEASE_RESET(); - __SPI5_CLK_DISABLE(); + __HAL_RCC_SPI5_FORCE_RESET(); + __HAL_RCC_SPI5_RELEASE_RESET(); + __HAL_RCC_SPI5_CLK_DISABLE(); #endif #if defined(MICROPY_HW_SPI6_SCK) } else if (spi->Instance == SPI6) { - __SPI6_FORCE_RESET(); - __SPI6_RELEASE_RESET(); - __SPI6_CLK_DISABLE(); + __HAL_RCC_SPI6_FORCE_RESET(); + __HAL_RCC_SPI6_RELEASE_RESET(); + __HAL_RCC_SPI6_CLK_DISABLE(); #endif } } -STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t timeout) { - // Note: we can't use WFI to idle in this loop because the DMA completion - // interrupt may occur before the WFI. Hence we miss it and have to wait - // until the next sys-tick (up to 1ms). - uint32_t start = HAL_GetTick(); - while (HAL_SPI_GetState(spi) != HAL_SPI_STATE_READY) { - if (HAL_GetTick() - start >= timeout) { +STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t t_start, uint32_t timeout) { + volatile HAL_SPI_StateTypeDef *state = &spi->spi->State; + for (;;) { + // Do an atomic check of the state; WFI will exit even if IRQs are disabled + uint32_t irq_state = disable_irq(); + if (*state == HAL_SPI_STATE_READY) { + enable_irq(irq_state); + return HAL_OK; + } + __WFI(); + enable_irq(irq_state); + if (HAL_GetTick() - t_start >= timeout) { return HAL_TIMEOUT; } } @@ -407,11 +424,13 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t // and use that value for the baudrate in the formula, plus a small constant. #define SPI_TRANSFER_TIMEOUT(len) ((len) + 100) -STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) { +STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) { // Note: there seems to be a problem sending 1 byte using DMA the first // time directly after the SPI/DMA is initialised. The cause of this is // unknown but we sidestep the issue by using polling for 1 byte transfer. + // Note: DMA transfers are limited to 65535 bytes at a time. + HAL_StatusTypeDef status; if (dest == NULL) { @@ -424,10 +443,20 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s self->spi->hdmatx = &tx_dma; self->spi->hdmarx = NULL; MP_HAL_CLEAN_DCACHE(src, len); - status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, timeout); - } + uint32_t t_start = HAL_GetTick(); + do { + uint32_t l = MIN(len, 65535); + status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, l); + if (status != HAL_OK) { + break; + } + status = spi_wait_dma_finished(self, t_start, timeout); + if (status != HAL_OK) { + break; + } + len -= l; + src += l; + } while (len); dma_deinit(self->tx_dma_descr); } } else if (src == NULL) { @@ -446,10 +475,20 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s dma_init(&rx_dma, self->rx_dma_descr, self->spi); self->spi->hdmarx = &rx_dma; MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); - status = HAL_SPI_Receive_DMA(self->spi, dest, len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, timeout); - } + uint32_t t_start = HAL_GetTick(); + do { + uint32_t l = MIN(len, 65535); + status = HAL_SPI_Receive_DMA(self->spi, dest, l); + if (status != HAL_OK) { + break; + } + status = spi_wait_dma_finished(self, t_start, timeout); + if (status != HAL_OK) { + break; + } + len -= l; + dest += l; + } while (len); if (self->spi->hdmatx != NULL) { dma_deinit(self->tx_dma_descr); } @@ -467,10 +506,21 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s self->spi->hdmarx = &rx_dma; MP_HAL_CLEAN_DCACHE(src, len); MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); - status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, timeout); - } + uint32_t t_start = HAL_GetTick(); + do { + uint32_t l = MIN(len, 65535); + status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, l); + if (status != HAL_OK) { + break; + } + status = spi_wait_dma_finished(self, t_start, timeout); + if (status != HAL_OK) { + break; + } + len -= l; + src += l; + dest += l; + } while (len); dma_deinit(self->tx_dma_descr); dma_deinit(self->rx_dma_descr); } @@ -481,10 +531,14 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s } } -STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool legacy) { +STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) { + SPI_HandleTypeDef *spi = spi_obj->spi; + uint spi_num = 1; // default to SPI1 if (spi->Instance == SPI2) { spi_num = 2; } + #if defined(SPI3) else if (spi->Instance == SPI3) { spi_num = 3; } + #endif #if defined(SPI4) else if (spi->Instance == SPI4) { spi_num = 4; } #endif @@ -500,6 +554,9 @@ STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool lega if (spi->Init.Mode == SPI_MODE_MASTER) { // compute baudrate uint spi_clock; + #if defined(STM32F0) + spi_clock = HAL_RCC_GetPCLK1Freq(); + #else if (spi->Instance == SPI2 || spi->Instance == SPI3) { // SPI2 and SPI3 are on APB1 spi_clock = HAL_RCC_GetPCLK1Freq(); @@ -507,6 +564,7 @@ STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool lega // SPI1, SPI4, SPI5 and SPI6 are on APB2 spi_clock = HAL_RCC_GetPCLK2Freq(); } + #endif uint log_prescaler = (spi->Init.BaudRatePrescaler >> 3) + 1; uint baudrate = spi_clock >> log_prescaler; if (legacy) { @@ -520,7 +578,7 @@ STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool lega mp_printf(print, ", SPI.SLAVE"); } mp_printf(print, ", polarity=%u, phase=%u, bits=%u", spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 0 : 1, spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16); - if (spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED) { + if (spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) { mp_printf(print, ", crc=0x%x", spi->Init.CRCPolynomial); } } @@ -530,13 +588,19 @@ STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool lega /******************************************************************************/ /* MicroPython bindings for legacy pyb API */ -SPI_HandleTypeDef *spi_get_handle(mp_obj_t o) { - if (!MP_OBJ_IS_TYPE(o, &pyb_spi_type)) { - mp_raise_ValueError("expecting an SPI object"); - } - pyb_spi_obj_t *self = o; - return self->spi; -} +typedef struct _pyb_spi_obj_t { + mp_obj_base_t base; + const spi_t *spi; +} pyb_spi_obj_t; + +STATIC const pyb_spi_obj_t pyb_spi_obj[] = { + {{&pyb_spi_type}, &spi_obj[0]}, + {{&pyb_spi_type}, &spi_obj[1]}, + {{&pyb_spi_type}, &spi_obj[2]}, + {{&pyb_spi_type}, &spi_obj[3]}, + {{&pyb_spi_type}, &spi_obj[4]}, + {{&pyb_spi_type}, &spi_obj[5]}, +}; STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_spi_obj_t *self = self_in; @@ -569,7 +633,7 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, size_t n_args, co mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // set the SPI configuration values - SPI_InitTypeDef *init = &self->spi->Init; + SPI_InitTypeDef *init = &self->spi->spi->Init; init->Mode = args[0].u_int; spi_set_params(self->spi, args[2].u_int, args[1].u_int, args[3].u_int, args[4].u_int, @@ -577,12 +641,12 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, size_t n_args, co init->Direction = args[5].u_int; init->NSS = args[7].u_int; - init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLED : SPI_TIMODE_DISABLED; + init->TIMode = args[9].u_bool ? SPI_TIMODE_ENABLE : SPI_TIMODE_DISABLE; if (args[10].u_obj == mp_const_none) { - init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLE; init->CRCPolynomial = 0; } else { - init->CRCCalculation = SPI_CRCCALCULATION_ENABLED; + init->CRCCalculation = SPI_CRCCALCULATION_ENABLE; init->CRCPolynomial = mp_obj_get_int(args[10].u_obj); } @@ -667,7 +731,7 @@ STATIC mp_obj_t pyb_spi_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); // send the data - spi_transfer(self, bufinfo.len, bufinfo.buf, NULL, args[1].u_int); + spi_transfer(self->spi, bufinfo.len, bufinfo.buf, NULL, args[1].u_int); return mp_const_none; } @@ -701,7 +765,7 @@ STATIC mp_obj_t pyb_spi_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); // receive the data - spi_transfer(self, vstr.len, NULL, (uint8_t*)vstr.buf, args[1].u_int); + spi_transfer(self->spi, vstr.len, NULL, (uint8_t*)vstr.buf, args[1].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { @@ -771,7 +835,7 @@ STATIC mp_obj_t pyb_spi_send_recv(size_t n_args, const mp_obj_t *pos_args, mp_ma } // do the transfer - spi_transfer(self, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int); + spi_transfer(self->spi, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.buf, args[2].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { @@ -819,7 +883,8 @@ STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); STATIC void spi_transfer_machine(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { - spi_transfer((pyb_spi_obj_t*)self_in, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); + pyb_spi_obj_t *self = (pyb_spi_obj_t*)self_in; + spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); } STATIC const mp_machine_spi_p_t pyb_spi_p = { @@ -840,21 +905,21 @@ const mp_obj_type_t pyb_spi_type = { typedef struct _machine_hard_spi_obj_t { mp_obj_base_t base; - const pyb_spi_obj_t *pyb; + const spi_t *spi; } machine_hard_spi_obj_t; STATIC const machine_hard_spi_obj_t machine_hard_spi_obj[] = { - {{&machine_hard_spi_type}, &pyb_spi_obj[0]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[1]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[2]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[3]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[4]}, - {{&machine_hard_spi_type}, &pyb_spi_obj[5]}, + {{&machine_hard_spi_type}, &spi_obj[0]}, + {{&machine_hard_spi_type}, &spi_obj[1]}, + {{&machine_hard_spi_type}, &spi_obj[2]}, + {{&machine_hard_spi_type}, &spi_obj[3]}, + {{&machine_hard_spi_type}, &spi_obj[4]}, + {{&machine_hard_spi_type}, &spi_obj[5]}, }; STATIC void machine_hard_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; - spi_print(print, self->pyb->spi, false); + spi_print(print, self->spi, false); } mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -885,23 +950,23 @@ mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_args, siz } // set the SPI configuration values - SPI_InitTypeDef *init = &self->pyb->spi->Init; + SPI_InitTypeDef *init = &self->spi->spi->Init; init->Mode = SPI_MODE_MASTER; // these parameters are not currently configurable init->Direction = SPI_DIRECTION_2LINES; init->NSS = SPI_NSS_SOFT; - init->TIMode = SPI_TIMODE_DISABLED; - init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->TIMode = SPI_TIMODE_DISABLE; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLE; init->CRCPolynomial = 0; // set configurable paramaters - spi_set_params(self->pyb->spi, 0xffffffff, args[ARG_baudrate].u_int, + spi_set_params(self->spi, 0xffffffff, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int, args[ARG_firstbit].u_int); // init the SPI bus - spi_init(self->pyb->spi, false); + spi_init(self->spi, false); return MP_OBJ_FROM_PTR(self); } @@ -921,22 +986,22 @@ STATIC void machine_hard_spi_init(mp_obj_base_t *self_in, size_t n_args, const m mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); // set the SPI configuration values - spi_set_params(self->pyb->spi, 0xffffffff, args[ARG_baudrate].u_int, + spi_set_params(self->spi, 0xffffffff, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int, args[ARG_firstbit].u_int); // re-init the SPI bus - spi_init(self->pyb->spi, false); + spi_init(self->spi, false); } STATIC void machine_hard_spi_deinit(mp_obj_base_t *self_in) { machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; - spi_deinit(self->pyb->spi); + spi_deinit(self->spi); } STATIC void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in; - spi_transfer(self->pyb, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); + spi_transfer(self->spi, len, src, dest, SPI_TRANSFER_TIMEOUT(len)); } STATIC const mp_machine_spi_p_t machine_hard_spi_p = { @@ -953,3 +1018,15 @@ const mp_obj_type_t machine_hard_spi_type = { .protocol = &machine_hard_spi_p, .locals_dict = (mp_obj_t)&mp_machine_spi_locals_dict, }; + +const spi_t *spi_from_mp_obj(mp_obj_t o) { + if (MP_OBJ_IS_TYPE(o, &pyb_spi_type)) { + pyb_spi_obj_t *self = o; + return self->spi; + } else if (MP_OBJ_IS_TYPE(o, &machine_hard_spi_type)) { + machine_hard_spi_obj_t *self = o;; + return self->spi; + } else { + mp_raise_TypeError("expecting an SPI object"); + } +} diff --git a/ports/stm32/spi.h b/ports/stm32/spi.h index eda109a7ef..41f91b2896 100644 --- a/ports/stm32/spi.h +++ b/ports/stm32/spi.h @@ -23,8 +23,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_SPI_H -#define MICROPY_INCLUDED_STMHAL_SPI_H +#ifndef MICROPY_INCLUDED_STM32_SPI_H +#define MICROPY_INCLUDED_STM32_SPI_H + +#include "dma.h" + +typedef struct _spi_t { + SPI_HandleTypeDef *spi; + const dma_descr_t *tx_dma_descr; + const dma_descr_t *rx_dma_descr; +} spi_t; extern SPI_HandleTypeDef SPIHandle1; extern SPI_HandleTypeDef SPIHandle2; @@ -32,12 +40,15 @@ extern SPI_HandleTypeDef SPIHandle3; extern SPI_HandleTypeDef SPIHandle4; extern SPI_HandleTypeDef SPIHandle5; extern SPI_HandleTypeDef SPIHandle6; + +extern const spi_t spi_obj[6]; + extern const mp_obj_type_t pyb_spi_type; extern const mp_obj_type_t machine_soft_spi_type; extern const mp_obj_type_t machine_hard_spi_type; void spi_init0(void); -void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin); -SPI_HandleTypeDef *spi_get_handle(mp_obj_t o); +void spi_init(const spi_t *spi, bool enable_nss_pin); +const spi_t *spi_from_mp_obj(mp_obj_t o); -#endif // MICROPY_INCLUDED_STMHAL_SPI_H +#endif // MICROPY_INCLUDED_STM32_SPI_H diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c new file mode 100644 index 0000000000..368e639665 --- /dev/null +++ b/ports/stm32/spibdev.c @@ -0,0 +1,85 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/mperrno.h" +#include "irq.h" +#include "led.h" +#include "storage.h" + +#if MICROPY_HW_ENABLE_STORAGE + +int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { + switch (op) { + case BDEV_IOCTL_INIT: + bdev->spiflash.config = (const mp_spiflash_config_t*)arg; + mp_spiflash_init(&bdev->spiflash); + bdev->flash_tick_counter_last_write = 0; + return 0; + + case BDEV_IOCTL_IRQ_HANDLER: + if ((bdev->spiflash.flags & 1) && HAL_GetTick() - bdev->flash_tick_counter_last_write >= 1000) { + mp_spiflash_cache_flush(&bdev->spiflash); + led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off + } + return 0; + + case BDEV_IOCTL_SYNC: + if (bdev->spiflash.flags & 1) { + // we must disable USB irqs to prevent MSC contention with SPI flash + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + mp_spiflash_cache_flush(&bdev->spiflash); + led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off + restore_irq_pri(basepri); + } + return 0; + } + return -MP_EINVAL; +} + +int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { + // we must disable USB irqs to prevent MSC contention with SPI flash + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + mp_spiflash_cached_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); + restore_irq_pri(basepri); + + return 0; +} + +int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { + // we must disable USB irqs to prevent MSC contention with SPI flash + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + int ret = mp_spiflash_cached_write(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src); + if (bdev->spiflash.flags & 1) { + led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on + bdev->flash_tick_counter_last_write = HAL_GetTick(); + } + restore_irq_pri(basepri); + + return ret; +} + +#endif diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index f1ac9b6b85..a2a8d0f2e5 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -84,8 +84,12 @@ #include "usb.h" extern void __fatal_error(const char*); +#if defined(MICROPY_HW_USB_FS) extern PCD_HandleTypeDef pcd_fs_handle; +#endif +#if defined(MICROPY_HW_USB_HS) extern PCD_HandleTypeDef pcd_hs_handle; +#endif /******************************************************************************/ /* Cortex-M4 Processor Exceptions Handlers */ @@ -143,9 +147,11 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) { NVIC_SystemReset(); } + #if MICROPY_HW_ENABLE_USB // We need to disable the USB so it doesn't try to write data out on // the VCP and then block indefinitely waiting for the buffer to drain. pyb_usb_flags = 0; + #endif mp_hal_stdout_tx_str("HardFault\r\n"); @@ -159,6 +165,7 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) { print_reg("PC ", regs->pc); print_reg("XPSR ", regs->xpsr); + #if __CORTEX_M >= 3 uint32_t cfsr = SCB->CFSR; print_reg("HFSR ", SCB->HFSR); @@ -169,6 +176,7 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) { if (cfsr & 0x8000) { print_reg("BFAR ", SCB->BFAR); } + #endif if ((void*)&_ram_start <= (void*)regs && (void*)regs < (void*)&_ram_end) { mp_hal_stdout_tx_str("Stack:\r\n"); @@ -201,6 +209,17 @@ void HardFault_Handler(void) { // main stack pointer (aka MSP). If CONTROL.SPSEL is 1, then the exception // was stacked up using the process stack pointer (aka PSP). + #if __CORTEX_M == 0 + __asm volatile( + " mov r0, lr \n" + " lsr r0, r0, #3 \n" // Shift Bit 3 into carry to see which stack pointer we should use. + " mrs r0, msp \n" // Make R0 point to main stack pointer + " bcc .use_msp \n" // Keep MSP in R0 if SPSEL (carry) is 0 + " mrs r0, psp \n" // Make R0 point to process stack pointer + " .use_msp: \n" + " b HardFault_C_Handler \n" // Off to C land + ); + #else __asm volatile( " tst lr, #4 \n" // Test Bit 3 to see which stack pointer we should use. " ite eq \n" // Tell the assembler that the nest 2 instructions are if-then-else @@ -208,6 +227,7 @@ void HardFault_Handler(void) { " mrsne r0, psp \n" // Make R0 point to process stack pointer " b HardFault_C_Handler \n" // Off to C land ); + #endif } /** @@ -304,9 +324,11 @@ void SysTick_Handler(void) { // be generalised in the future then a dispatch table can be used as // follows: ((void(*)(void))(systick_dispatch[uwTick & 0xf]))(); + #if MICROPY_HW_ENABLE_STORAGE if (STORAGE_IDLE_TICK(uwTick)) { NVIC->STIR = FLASH_IRQn; } + #endif if (DMA_IDLE_ENABLED() && DMA_IDLE_TICK(uwTick)) { dma_idle_handler(uwTick); @@ -337,14 +359,14 @@ void SysTick_Handler(void) { * @param None * @retval None */ -#if defined(USE_USB_FS) +#if MICROPY_HW_USB_FS void OTG_FS_IRQHandler(void) { IRQ_ENTER(OTG_FS_IRQn); HAL_PCD_IRQHandler(&pcd_fs_handle); IRQ_EXIT(OTG_FS_IRQn); } #endif -#if defined(USE_USB_HS) +#if MICROPY_HW_USB_HS void OTG_HS_IRQHandler(void) { IRQ_ENTER(OTG_HS_IRQn); HAL_PCD_IRQHandler(&pcd_hs_handle); @@ -352,7 +374,7 @@ void OTG_HS_IRQHandler(void) { } #endif -#if defined(USE_USB_FS) || defined(USE_USB_HS) +#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS /** * @brief This function handles USB OTG Common FS/HS Wakeup functions. * @param *pcd_handle for FS or HS @@ -367,7 +389,7 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { /* Configures system clock after wake-up from STOP: enable HSE, PLL and select PLL as system clock source (HSE and PLL are disabled in STOP mode) */ - __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + __HAL_RCC_HSE_CONFIG(MICROPY_HW_CLK_HSE_STATE); /* Wait till HSE is ready */ while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) @@ -383,8 +405,13 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { /* Select PLL as SYSCLK */ MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK); + #if defined(STM32H7) + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) + {} + #else while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) {} + #endif /* ungate PHY clock */ __HAL_PCD_UNGATE_PHYCLOCK(pcd_handle); @@ -393,7 +420,7 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { } #endif -#if defined(USE_USB_FS) +#if MICROPY_HW_USB_FS /** * @brief This function handles USB OTG FS Wakeup IRQ Handler. * @param None @@ -411,7 +438,7 @@ void OTG_FS_WKUP_IRQHandler(void) { } #endif -#if defined(USE_USB_HS) +#if MICROPY_HW_USB_HS /** * @brief This function handles USB OTG HS Wakeup IRQ Handler. * @param None @@ -448,8 +475,10 @@ void FLASH_IRQHandler(void) { HAL_FLASH_IRQHandler(); } */ + #if MICROPY_HW_ENABLE_STORAGE // This call the storage IRQ handler, to check if the flash cache needs flushing storage_irq_handler(); + #endif IRQ_EXIT(FLASH_IRQn); } @@ -515,7 +544,7 @@ void PVD_IRQHandler(void) { IRQ_EXIT(PVD_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void PVD_PVM_IRQHandler(void) { IRQ_ENTER(PVD_PVM_IRQn); Handle_EXTI_Irq(EXTI_PVD_OUTPUT); @@ -550,13 +579,52 @@ void RTC_WKUP_IRQHandler(void) { IRQ_EXIT(RTC_WKUP_IRQn); } +#if defined(STM32F0) + +void RTC_IRQHandler(void) { + IRQ_ENTER(RTC_IRQn); + RTC->ISR &= ~(1 << 10); // clear wakeup interrupt flag + Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback + IRQ_EXIT(RTC_IRQn); +} + +void EXTI0_1_IRQHandler(void) { + IRQ_ENTER(EXTI0_1_IRQn); + Handle_EXTI_Irq(0); + Handle_EXTI_Irq(1); + IRQ_EXIT(EXTI0_1_IRQn); +} + +void EXTI2_3_IRQHandler(void) { + IRQ_ENTER(EXTI2_3_IRQn); + Handle_EXTI_Irq(2); + Handle_EXTI_Irq(3); + IRQ_EXIT(EXTI2_3_IRQn); +} + +void EXTI4_15_IRQHandler(void) { + IRQ_ENTER(EXTI4_15_IRQn); + for (int i = 4; i <= 15; ++i) { + Handle_EXTI_Irq(i); + } + IRQ_EXIT(EXTI4_15_IRQn); +} + +void TIM1_BRK_UP_TRG_COM_IRQHandler(void) { + IRQ_ENTER(TIM1_BRK_UP_TRG_COM_IRQn); + timer_irq_handler(1); + IRQ_EXIT(TIM1_BRK_UP_TRG_COM_IRQn); +} + +#endif + void TIM1_BRK_TIM9_IRQHandler(void) { IRQ_ENTER(TIM1_BRK_TIM9_IRQn); timer_irq_handler(9); IRQ_EXIT(TIM1_BRK_TIM9_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM1_BRK_TIM15_IRQHandler(void) { IRQ_ENTER(TIM1_BRK_TIM15_IRQn); timer_irq_handler(15); @@ -571,7 +639,7 @@ void TIM1_UP_TIM10_IRQHandler(void) { IRQ_EXIT(TIM1_UP_TIM10_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM1_UP_TIM16_IRQHandler(void) { IRQ_ENTER(TIM1_UP_TIM16_IRQn); timer_irq_handler(1); @@ -586,7 +654,7 @@ void TIM1_TRG_COM_TIM11_IRQHandler(void) { IRQ_EXIT(TIM1_TRG_COM_TIM11_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM1_TRG_COM_TIM17_IRQHandler(void) { IRQ_ENTER(TIM1_TRG_COM_TIM17_IRQn); timer_irq_handler(17); @@ -655,7 +723,7 @@ void TIM8_UP_TIM13_IRQHandler(void) { IRQ_EXIT(TIM8_UP_TIM13_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM8_UP_IRQHandler(void) { IRQ_ENTER(TIM8_UP_IRQn); timer_irq_handler(8); @@ -689,6 +757,21 @@ void USART2_IRQHandler(void) { IRQ_EXIT(USART2_IRQn); } +#if defined(STM32F0) + +void USART3_8_IRQHandler(void) { + IRQ_ENTER(USART3_8_IRQn); + uart_irq_handler(3); + uart_irq_handler(4); + uart_irq_handler(5); + uart_irq_handler(6); + uart_irq_handler(7); + uart_irq_handler(8); + IRQ_EXIT(USART3_8_IRQn); +} + +#else + void USART3_IRQHandler(void) { IRQ_ENTER(USART3_IRQn); uart_irq_handler(3); @@ -713,7 +796,7 @@ void USART6_IRQHandler(void) { IRQ_EXIT(USART6_IRQn); } -#if defined(MICROPY_HW_UART7_TX) +#if defined(UART8) void UART7_IRQHandler(void) { IRQ_ENTER(UART7_IRQn); uart_irq_handler(7); @@ -721,7 +804,7 @@ void UART7_IRQHandler(void) { } #endif -#if defined(MICROPY_HW_UART8_TX) +#if defined(UART8) void UART8_IRQHandler(void) { IRQ_ENTER(UART8_IRQn); uart_irq_handler(8); @@ -729,7 +812,9 @@ void UART8_IRQHandler(void) { } #endif -#if MICROPY_HW_ENABLE_CAN +#endif + +#if defined(MICROPY_HW_CAN1_TX) void CAN1_RX0_IRQHandler(void) { IRQ_ENTER(CAN1_RX0_IRQn); can_rx_irq_handler(PYB_CAN_1, CAN_FIFO0); @@ -742,6 +827,14 @@ void CAN1_RX1_IRQHandler(void) { IRQ_EXIT(CAN1_RX1_IRQn); } +void CAN1_SCE_IRQHandler(void) { + IRQ_ENTER(CAN1_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_1); + IRQ_EXIT(CAN1_SCE_IRQn); +} +#endif + +#if defined(MICROPY_HW_CAN2_TX) void CAN2_RX0_IRQHandler(void) { IRQ_ENTER(CAN2_RX0_IRQn); can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0); @@ -753,7 +846,15 @@ void CAN2_RX1_IRQHandler(void) { can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1); IRQ_EXIT(CAN2_RX1_IRQn); } -#endif // MICROPY_HW_ENABLE_CAN + +void CAN2_SCE_IRQHandler(void) { + IRQ_ENTER(CAN2_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_2); + IRQ_EXIT(CAN2_SCE_IRQn); +} +#endif + +#if MICROPY_PY_PYB_LEGACY #if defined(MICROPY_HW_I2C1_SCL) void I2C1_EV_IRQHandler(void) { @@ -796,3 +897,19 @@ void I2C3_ER_IRQHandler(void) { IRQ_EXIT(I2C3_ER_IRQn); } #endif // defined(MICROPY_HW_I2C3_SCL) + +#if defined(MICROPY_HW_I2C4_SCL) +void I2C4_EV_IRQHandler(void) { + IRQ_ENTER(I2C4_EV_IRQn); + i2c_ev_irq_handler(4); + IRQ_EXIT(I2C4_EV_IRQn); +} + +void I2C4_ER_IRQHandler(void) { + IRQ_ENTER(I2C4_ER_IRQn); + i2c_er_irq_handler(4); + IRQ_EXIT(I2C4_ER_IRQn); +} +#endif // defined(MICROPY_HW_I2C4_SCL) + +#endif // MICROPY_PY_PYB_LEGACY diff --git a/ports/stm32/stm32_it.h b/ports/stm32/stm32_it.h index b498dee8da..46523e5673 100644 --- a/ports/stm32/stm32_it.h +++ b/ports/stm32/stm32_it.h @@ -25,8 +25,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_STM32_IT_H -#define MICROPY_INCLUDED_STMHAL_STM32_IT_H +#ifndef MICROPY_INCLUDED_STM32_STM32_IT_H +#define MICROPY_INCLUDED_STM32_STM32_IT_H /** ****************************************************************************** @@ -76,11 +76,7 @@ void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); -#ifdef USE_USB_FS void OTG_FS_IRQHandler(void); -#endif -#ifdef USE_USB_HS void OTG_HS_IRQHandler(void); -#endif -#endif // MICROPY_INCLUDED_STMHAL_STM32_IT_H +#endif // MICROPY_INCLUDED_STM32_STM32_IT_H diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c index 4b329c2dbb..761db0b525 100644 --- a/ports/stm32/storage.c +++ b/ports/stm32/storage.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,191 +27,39 @@ #include #include -#include "py/obj.h" #include "py/runtime.h" -#include "lib/oofatfs/ff.h" #include "extmod/vfs_fat.h" -#include "systick.h" #include "led.h" -#include "flash.h" #include "storage.h" #include "irq.h" -#if defined(MICROPY_HW_SPIFLASH_SIZE_BITS) -#define USE_INTERNAL (0) -#else -#define USE_INTERNAL (1) -#endif - -#if USE_INTERNAL - -#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) - -#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k -#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM -#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 -#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k - -// enable this to get an extra 64k of storage (uses the last sector of the flash) -#if 0 -#define FLASH_MEM_SEG2_START_ADDR (0x080e0000) // sector 11 -#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 11: 128k -#endif - -#elif defined(STM32F401xE) || defined(STM32F411xE) || defined(STM32F446xx) - -STATIC byte flash_cache_mem[0x4000] __attribute__((aligned(4))); // 16k -#define CACHE_MEM_START_ADDR (&flash_cache_mem[0]) -#define FLASH_SECTOR_SIZE_MAX (0x4000) // 16k max due to size of cache buffer -#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 -#define FLASH_MEM_SEG1_NUM_BLOCKS (128) // sectors 1,2,3,4: 16k+16k+16k+16k(of 64k)=64k - -#elif defined(STM32F429xx) - -#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k -#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM -#define FLASH_MEM_SEG1_START_ADDR (0x08004000) // sector 1 -#define FLASH_MEM_SEG1_NUM_BLOCKS (224) // sectors 1,2,3,4: 16k+16k+16k+64k=112k - -#elif defined(STM32F439xx) - -#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k -#define FLASH_SECTOR_SIZE_MAX (0x10000) // 64k max, size of CCM -#define FLASH_MEM_SEG1_START_ADDR (0x08100000) // sector 12 -#define FLASH_MEM_SEG1_NUM_BLOCKS (384) // sectors 12,13,14,15,16,17: 16k+16k+16k+16k+64k+64k(of 128k)=192k -#define FLASH_MEM_SEG2_START_ADDR (0x08140000) // sector 18 -#define FLASH_MEM_SEG2_NUM_BLOCKS (128) // sector 18: 64k(of 128k) - -#elif defined(STM32F746xx) || defined(STM32F767xx) || defined(STM32F769xx) - -// The STM32F746 doesn't really have CCRAM, so we use the 64K DTCM for this. - -#define CACHE_MEM_START_ADDR (0x20000000) // DTCM data RAM, 64k -#define FLASH_SECTOR_SIZE_MAX (0x08000) // 32k max -#define FLASH_MEM_SEG1_START_ADDR (0x08008000) // sector 1 -#define FLASH_MEM_SEG1_NUM_BLOCKS (192) // sectors 1,2,3: 32k+32k+32=96k - -#elif defined(STM32L475xx) || defined(STM32L476xx) - -extern uint8_t _flash_fs_start; -extern uint8_t _flash_fs_end; - -// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this. -#define CACHE_MEM_START_ADDR (0x10000000) // SRAM2 data RAM, 32k -#define FLASH_SECTOR_SIZE_MAX (0x00800) // 2k max -#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start) -#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512) - -#else -#error "no storage support for this MCU" -#endif - -#if !defined(FLASH_MEM_SEG2_START_ADDR) -#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment -#define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment -#endif +#if MICROPY_HW_ENABLE_STORAGE #define FLASH_PART1_START_BLOCK (0x100) -#define FLASH_PART1_NUM_BLOCKS (FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) - -#define FLASH_FLAG_DIRTY (1) -#define FLASH_FLAG_FORCE_WRITE (2) -#define FLASH_FLAG_ERASED (4) -static bool flash_is_initialised = false; -static __IO uint8_t flash_flags = 0; -static uint32_t flash_cache_sector_id; -static uint32_t flash_cache_sector_start; -static uint32_t flash_cache_sector_size; -static uint32_t flash_tick_counter_last_write; - -static void flash_cache_flush(void) { - if (flash_flags & FLASH_FLAG_DIRTY) { - flash_flags |= FLASH_FLAG_FORCE_WRITE; - while (flash_flags & FLASH_FLAG_DIRTY) { - NVIC->STIR = FLASH_IRQn; - } - } -} - -static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) { - uint32_t flash_sector_start; - uint32_t flash_sector_size; - uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); - if (flash_sector_size > FLASH_SECTOR_SIZE_MAX) { - flash_sector_size = FLASH_SECTOR_SIZE_MAX; - } - if (flash_cache_sector_id != flash_sector_id) { - flash_cache_flush(); - memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size); - flash_cache_sector_id = flash_sector_id; - flash_cache_sector_start = flash_sector_start; - flash_cache_sector_size = flash_sector_size; - } - flash_flags |= FLASH_FLAG_DIRTY; - led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on - flash_tick_counter_last_write = HAL_GetTick(); - return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; -} - -static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) { - uint32_t flash_sector_start; - uint32_t flash_sector_size; - uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size); - if (flash_cache_sector_id == flash_sector_id) { - // in cache, copy from there - return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; - } - // not in cache, copy straight from flash - return (uint8_t*)flash_addr; -} - -#else - -#include "drivers/memory/spiflash.h" -#include "genhdr/pins.h" - -#define FLASH_PART1_START_BLOCK (0x100) -#define FLASH_PART1_NUM_BLOCKS (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) - -static bool flash_is_initialised = false; - -STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { - .base = {&mp_machine_soft_spi_type}, - .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY, - .polarity = 0, - .phase = 0, - .sck = &MICROPY_HW_SPIFLASH_SCK, - .mosi = &MICROPY_HW_SPIFLASH_MOSI, - .miso = &MICROPY_HW_SPIFLASH_MISO, -}; - -STATIC const mp_spiflash_t spiflash = { - .cs = &MICROPY_HW_SPIFLASH_CS, - .spi = (mp_obj_base_t*)&spiflash_spi_bus.base, -}; +#if defined(MICROPY_HW_BDEV2_IOCTL) +#define FLASH_PART2_START_BLOCK (FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) #endif +static bool storage_is_initialised = false; + void storage_init(void) { - if (!flash_is_initialised) { - #if USE_INTERNAL - flash_flags = 0; - flash_cache_sector_id = 0; - flash_tick_counter_last_write = 0; - #else - mp_spiflash_init((mp_spiflash_t*)&spiflash); - #endif - flash_is_initialised = true; - } + if (!storage_is_initialised) { + storage_is_initialised = true; - #if USE_INTERNAL - // Enable the flash IRQ, which is used to also call our storage IRQ handler - // It needs to go at a higher priority than all those components that rely on - // the flash storage (eg higher than USB MSC). - HAL_NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH, IRQ_SUBPRI_FLASH); - HAL_NVIC_EnableIRQ(FLASH_IRQn); - #endif + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_INIT, 0); + + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_INIT, 0); + #endif + + // Enable the flash IRQ, which is used to also call our storage IRQ handler + // It needs to go at a higher priority than all those components that rely on + // the flash storage (eg higher than USB MSC). + NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH); + HAL_NVIC_EnableIRQ(FLASH_IRQn); + } } uint32_t storage_get_block_size(void) { @@ -219,59 +67,24 @@ uint32_t storage_get_block_size(void) { } uint32_t storage_get_block_count(void) { - return FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS; + #if defined(MICROPY_HW_BDEV2_IOCTL) + return FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0); + #else + return FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0); + #endif } void storage_irq_handler(void) { - #if USE_INTERNAL - - if (!(flash_flags & FLASH_FLAG_DIRTY)) { - return; - } - - // This code uses interrupts to erase the flash - /* - if (flash_erase_state == 0) { - flash_erase_it(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); - flash_erase_state = 1; - return; - } - - if (flash_erase_state == 1) { - // wait for erase - // TODO add timeout - #define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET) - if (!flash_erase_done()) { - return; - } - flash_erase_state = 2; - } - */ - - // This code erases the flash directly, waiting for it to finish - if (!(flash_flags & FLASH_FLAG_ERASED)) { - flash_erase(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); - flash_flags |= FLASH_FLAG_ERASED; - return; - } - - // If not a forced write, wait at least 5 seconds after last write to flush - // On file close and flash unmount we get a forced write, so we can afford to wait a while - if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || sys_tick_has_passed(flash_tick_counter_last_write, 5000)) { - // sync the cache RAM buffer by writing it to the flash page - flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); - // clear the flash flags now that we have a clean cache - flash_flags = 0; - // indicate a clean cache with LED off - led_state(PYB_LED_RED, 0); - } - + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0); + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_IRQ_HANDLER, 0); #endif } void storage_flush(void) { - #if USE_INTERNAL - flash_cache_flush(); + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_SYNC, 0); + #if defined(MICROPY_HW_BDEV2_IOCTL) + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_SYNC, 0); #endif } @@ -311,25 +124,6 @@ static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_blo buf[15] = num_blocks >> 24; } -#if USE_INTERNAL - -static uint32_t convert_block_to_flash_addr(uint32_t block) { - if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) { - // a block in partition 1 - block -= FLASH_PART1_START_BLOCK; - if (block < FLASH_MEM_SEG1_NUM_BLOCKS) { - return FLASH_MEM_SEG1_START_ADDR + block * FLASH_BLOCK_SIZE; - } else if (block < FLASH_MEM_SEG1_NUM_BLOCKS + FLASH_MEM_SEG2_NUM_BLOCKS) { - return FLASH_MEM_SEG2_START_ADDR + (block - FLASH_MEM_SEG1_NUM_BLOCKS) * FLASH_BLOCK_SIZE; - } - // can add more flash segments here if needed, following above pattern - } - // bad block - return -1; -} - -#endif - bool storage_read_block(uint8_t *dest, uint32_t block) { //printf("RD %u\n", block); if (block == 0) { @@ -339,8 +133,12 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { dest[i] = 0; } - build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, FLASH_PART1_NUM_BLOCKS); + build_partition(dest + 446, 0, 0x01 /* FAT12 */, FLASH_PART1_START_BLOCK, MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)); + #if defined(MICROPY_HW_BDEV2_IOCTL) + build_partition(dest + 462, 0, 0x01 /* FAT12 */, FLASH_PART2_START_BLOCK, MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)); + #else build_partition(dest + 462, 0, 0, 0, 0); + #endif build_partition(dest + 478, 0, 0, 0, 0); build_partition(dest + 494, 0, 0, 0, 0); @@ -349,39 +147,12 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { return true; + #if defined(MICROPY_HW_BDEV_READBLOCK) + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_READBLOCK(dest, block - FLASH_PART1_START_BLOCK); + #endif } else { - #if USE_INTERNAL - - // non-MBR block, get data from flash memory, possibly via cache - uint32_t flash_addr = convert_block_to_flash_addr(block); - if (flash_addr == -1) { - // bad block number - return false; - } - uint8_t *src = flash_cache_get_addr_for_read(flash_addr); - memcpy(dest, src, FLASH_BLOCK_SIZE); - return true; - - #else - - // non-MBR block, get data from SPI flash - - if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) { - // bad block number - return false; - } - - // we must disable USB irqs to prevent MSC contention with SPI flash - uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - - mp_spiflash_read((mp_spiflash_t*)&spiflash, - (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest); - - restore_irq_pri(basepri); - - return true; - - #endif + return false; } } @@ -390,44 +161,28 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { if (block == 0) { // can't write MBR, but pretend we did return true; - + #if defined(MICROPY_HW_BDEV_WRITEBLOCK) + } else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_WRITEBLOCK(src, block - FLASH_PART1_START_BLOCK); + #endif } else { - #if USE_INTERNAL - - // non-MBR block, copy to cache - uint32_t flash_addr = convert_block_to_flash_addr(block); - if (flash_addr == -1) { - // bad block number - return false; - } - uint8_t *dest = flash_cache_get_addr_for_write(flash_addr); - memcpy(dest, src, FLASH_BLOCK_SIZE); - return true; - - #else - - // non-MBR block, write to SPI flash - - if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) { - // bad block number - return false; - } - - // we must disable USB irqs to prevent MSC contention with SPI flash - uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - - int ret = mp_spiflash_write((mp_spiflash_t*)&spiflash, - (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src); - - restore_irq_pri(basepri); - - return ret == 0; - - #endif + return false; } } mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { + #if defined(MICROPY_HW_BDEV_READBLOCKS) + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_READBLOCKS(dest, block_num - FLASH_PART1_START_BLOCK, num_blocks); + } + #endif + + #if defined(MICROPY_HW_BDEV2_READBLOCKS) + if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV2_READBLOCKS(dest, block_num - FLASH_PART2_START_BLOCK, num_blocks); + } + #endif + for (size_t i = 0; i < num_blocks; i++) { if (!storage_read_block(dest + i * FLASH_BLOCK_SIZE, block_num + i)) { return 1; // error @@ -437,6 +192,18 @@ mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_bl } mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { + #if defined(MICROPY_HW_BDEV_WRITEBLOCKS) + if (FLASH_PART1_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART1_START_BLOCK + MICROPY_HW_BDEV_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV_WRITEBLOCKS(src, block_num - FLASH_PART1_START_BLOCK, num_blocks); + } + #endif + + #if defined(MICROPY_HW_BDEV2_WRITEBLOCKS) + if (FLASH_PART2_START_BLOCK <= block_num && block_num + num_blocks <= FLASH_PART2_START_BLOCK + MICROPY_HW_BDEV2_IOCTL(BDEV_IOCTL_NUM_BLOCKS, 0)) { + return MICROPY_HW_BDEV2_WRITEBLOCKS(src, block_num - FLASH_PART2_START_BLOCK, num_blocks); + } + #endif + for (size_t i = 0; i < num_blocks; i++) { if (!storage_write_block(src + i * FLASH_BLOCK_SIZE, block_num + i)) { return 1; // error @@ -519,3 +286,5 @@ void pyb_flash_init_vfs(fs_user_mount_t *vfs) { vfs->u.ioctl[0] = (mp_obj_t)&pyb_flash_ioctl_obj; vfs->u.ioctl[1] = (mp_obj_t)&pyb_flash_obj; } + +#endif diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 291e09a9ae..7250b6dbf9 100644 --- a/ports/stm32/storage.h +++ b/ports/stm32/storage.h @@ -23,14 +23,24 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_STORAGE_H -#define MICROPY_INCLUDED_STMHAL_STORAGE_H +#ifndef MICROPY_INCLUDED_STM32_STORAGE_H +#define MICROPY_INCLUDED_STM32_STORAGE_H + +#include "drivers/memory/spiflash.h" #define FLASH_BLOCK_SIZE (512) #define STORAGE_SYSTICK_MASK (0x1ff) // 512ms #define STORAGE_IDLE_TICK(tick) (((tick) & STORAGE_SYSTICK_MASK) == 2) +// Try to match Python-level VFS block protocol where possible for these constants +enum { + BDEV_IOCTL_INIT = 1, + BDEV_IOCTL_SYNC = 3, + BDEV_IOCTL_NUM_BLOCKS = 4, + BDEV_IOCTL_IRQ_HANDLER = 6, +}; + void storage_init(void); uint32_t storage_get_block_size(void); uint32_t storage_get_block_count(void); @@ -43,9 +53,22 @@ bool storage_write_block(const uint8_t *src, uint32_t block); mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks); mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); +int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg); +bool flash_bdev_readblock(uint8_t *dest, uint32_t block); +bool flash_bdev_writeblock(const uint8_t *src, uint32_t block); + +typedef struct _spi_bdev_t { + mp_spiflash_t spiflash; + uint32_t flash_tick_counter_last_write; +} spi_bdev_t; + +int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg); +int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks); +int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks); + extern const struct _mp_obj_type_t pyb_flash_type; struct _fs_user_mount_t; void pyb_flash_init_vfs(struct _fs_user_mount_t *vfs); -#endif // MICROPY_INCLUDED_STMHAL_STORAGE_H +#endif // MICROPY_INCLUDED_STM32_STORAGE_H diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c index b71a03181a..0cf0753bdf 100644 --- a/ports/stm32/system_stm32.c +++ b/ports/stm32/system_stm32.c @@ -107,24 +107,24 @@ void __fatal_error(const char *msg); * @{ */ -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) #define CONFIG_RCC_CR_1ST (RCC_CR_HSION) -#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLLON) #define CONFIG_RCC_PLLCFGR (0x24003010) -#if defined(MCU_SERIES_F4) +#if defined(STM32F4) const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; -#elif defined(MCU_SERIES_F7) +#elif defined(STM32F7) const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; #endif -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) #define CONFIG_RCC_CR_1ST (RCC_CR_MSION) -#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_HSION || RCC_CR_PLLON) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_HSION | RCC_CR_PLLON) #define CONFIG_RCC_PLLCFGR (0x00001000) /* * FIXME Do not know why I have to define these arrays here! they should be defined in the @@ -135,6 +135,17 @@ const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; const uint32_t MSIRangeTable[12] = {100000, 200000, 400000, 800000, 1000000, 2000000, \ 4000000, 8000000, 16000000, 24000000, 32000000, 48000000}; +#elif defined(STM32H7) + +#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) +#define CONFIG_RCC_CR_2ND (~0xEAF6ED7F) +#define CONFIG_RCC_PLLCFGR (0x00000000) + +#define SRAM_BASE D1_AXISRAM_BASE +#define FLASH_BASE FLASH_BANK1_BASE +uint32_t SystemD2Clock = 64000000; +const uint8_t D1CorePrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9}; + #else #error Unknown processor #endif @@ -204,7 +215,7 @@ void SystemInit(void) #endif /* Reset the RCC clock configuration to the default reset state ------------*/ - /* Set HSION bit */ + /* Set configured startup clk source */ RCC->CR |= CONFIG_RCC_CR_1ST; /* Reset CFGR register */ @@ -216,21 +227,62 @@ void SystemInit(void) /* Reset PLLCFGR register */ RCC->PLLCFGR = CONFIG_RCC_PLLCFGR; + #if defined(STM32H7) + /* Reset D1CFGR register */ + RCC->D1CFGR = 0x00000000; + + /* Reset D2CFGR register */ + RCC->D2CFGR = 0x00000000; + + /* Reset D3CFGR register */ + RCC->D3CFGR = 0x00000000; + + /* Reset PLLCKSELR register */ + RCC->PLLCKSELR = 0x00000000; + + /* Reset PLL1DIVR register */ + RCC->PLL1DIVR = 0x00000000; + + /* Reset PLL1FRACR register */ + RCC->PLL1FRACR = 0x00000000; + + /* Reset PLL2DIVR register */ + RCC->PLL2DIVR = 0x00000000; + + /* Reset PLL2FRACR register */ + RCC->PLL2FRACR = 0x00000000; + + /* Reset PLL3DIVR register */ + RCC->PLL3DIVR = 0x00000000; + + /* Reset PLL3FRACR register */ + RCC->PLL3FRACR = 0x00000000; + #endif + /* Reset HSEBYP bit */ RCC->CR &= (uint32_t)0xFFFBFFFF; /* Disable all interrupts */ - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) RCC->CIR = 0x00000000; - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) || defined(STM32H7) RCC->CIER = 0x00000000; #endif + #if defined(STM32H7) + /* Change the switch matrix read issuing capability to 1 for the AXI SRAM target (Target 7) */ + *((__IO uint32_t*)0x51008108) = 0x00000001; + #endif + /* Configure the Vector Table location add offset address ------------------*/ +#ifdef MICROPY_HW_VTOR + SCB->VTOR = MICROPY_HW_VTOR; +#else #ifdef VECT_TAB_SRAM SCB->VTOR = SRAM1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ +#endif #endif /* dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI */ @@ -319,29 +371,47 @@ void SystemInit(void) */ void SystemClock_Config(void) { - RCC_ClkInitTypeDef RCC_ClkInitStruct; - RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct; + RCC_OscInitTypeDef RCC_OscInitStruct; + #if defined(STM32H7) + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + #endif - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) - /* Enable Power Control clock */ - __PWR_CLK_ENABLE(); + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) - /* The voltage scaling allows optimizing the power consumption when the device is - clocked below the maximum system frequency, to update the voltage scaling value - regarding system frequency refer to product datasheet. */ - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); - #elif defined(MCU_SERIES_L4) + /* Enable Power Control clock */ + #if defined(STM32H7) + MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0); + #else + __PWR_CLK_ENABLE(); + #endif + + /* The voltage scaling allows optimizing the power consumption when the device is + clocked below the maximum system frequency, to update the voltage scaling value + regarding system frequency refer to product datasheet. */ + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + #elif defined(STM32L4) // Configure LSE Drive Capability __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); #endif + #if defined(STM32H7) + // Wait for PWR_FLAG_VOSRDY + while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) { + } + #endif + /* Enable HSE Oscillator and activate PLL with HSE as source */ - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.HSEState = MICROPY_HW_CLK_HSE_STATE; + RCC_OscInitStruct.HSIState = RCC_HSI_OFF; + #if defined(STM32H7) + RCC_OscInitStruct.CSIState = RCC_CSI_OFF; + #endif RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; - #elif defined(MCU_SERIES_L4) - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; + #elif defined(STM32L4) + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; @@ -352,12 +422,15 @@ void SystemClock_Config(void) /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + #if defined(STM32H7) + RCC_ClkInitStruct.ClockType |= (RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1); + #endif RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; #if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) #define FREQ_BKP BKP31R - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) #error Unsupported Processor #else #define FREQ_BKP BKP19R @@ -401,25 +474,56 @@ void SystemClock_Config(void) RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; RCC_OscInitStruct.PLL.PLLP = MICROPY_HW_CLK_PLLP; RCC_OscInitStruct.PLL.PLLQ = MICROPY_HW_CLK_PLLQ; - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) || defined(STM32H7) RCC_OscInitStruct.PLL.PLLR = MICROPY_HW_CLK_PLLR; #endif - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32H7) + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1; + RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; + RCC_OscInitStruct.PLL.PLLFRACN = 0; + #endif + + #if defined(STM32F4) || defined(STM32F7) + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + #elif defined(STM32H7) + RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; + RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; + RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; + RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; + RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; #endif #endif - if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - __fatal_error("HAL_RCC_OscConfig"); - } -#if defined(MCU_SERIES_F7) + if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + __fatal_error("HAL_RCC_OscConfig"); + } + +#if defined(STM32H7) + /* PLL3 for USB Clock */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB; + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL3; + PeriphClkInitStruct.PLL3.PLL3M = 4; + PeriphClkInitStruct.PLL3.PLL3N = 120; + PeriphClkInitStruct.PLL3.PLL3P = 2; + PeriphClkInitStruct.PLL3.PLL3Q = 5; + PeriphClkInitStruct.PLL3.PLL3R = 2; + PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_1; + PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE; + PeriphClkInitStruct.PLL3.PLL3FRACN = 0; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } +#endif + +#if defined(STM32F7) /* Activate the OverDrive to reach the 200 MHz Frequency */ if (HAL_PWREx_EnableOverDrive() != HAL_OK) { @@ -436,14 +540,28 @@ void SystemClock_Config(void) __fatal_error("HAL_RCC_ClockConfig"); } -#if defined(MCU_SERIES_F7) +#if defined(STM32H7) + /* Activate CSI clock mandatory for I/O Compensation Cell*/ + __HAL_RCC_CSI_ENABLE() ; + + /* Enable SYSCFG clock mandatory for I/O Compensation Cell */ + __HAL_RCC_SYSCFG_CLK_ENABLE() ; + + /* Enable the I/O Compensation Cell */ + HAL_EnableCompensationCell(); + + /* Enable the USB voltage level detector */ + HAL_PWREx_EnableUSBVoltageDetector(); +#endif + +#if defined(STM32F7) // The DFU bootloader changes the clocksource register from its default power // on reset value, so we set it back here, so the clocksources are the same // whether we were started from DFU or from a power on reset. RCC->DCKCFGR2 = 0; #endif -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) // Enable MSI-Hardware auto calibration mode with LSE HAL_RCCEx_EnableMSIPLLMode(); @@ -453,7 +571,7 @@ void SystemClock_Config(void) |RCC_PERIPHCLK_RNG |RCC_PERIPHCLK_RTC; PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; /* PLLSAI is used to clock USB, ADC, I2C1 and RNG. The frequency is - HSE(8MHz)/PLLM(2)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. See the STM32CubeMx + MSI(4MHz)/PLLM(1)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. See the STM32CubeMx application or the reference manual. */ PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1; @@ -480,17 +598,7 @@ void SystemClock_Config(void) HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); - HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); -#endif -} - -void HAL_MspInit(void) { -#if defined(MCU_SERIES_F7) - /* Enable I-Cache */ - SCB_EnableICache(); - - /* Enable D-Cache */ - SCB_EnableDCache(); + NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, TICK_INT_PRIORITY, 0)); #endif } diff --git a/ports/stm32/system_stm32f0.c b/ports/stm32/system_stm32f0.c new file mode 100644 index 0000000000..9d4b06e568 --- /dev/null +++ b/ports/stm32/system_stm32f0.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Taken from ST Cube library and modified. See below for original header. + */ + +/** + ****************************************************************************** + * @file system_stm32f0xx.c + * @author MCD Application Team + * @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File. + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#include STM32_HAL_H + +#ifndef HSE_VALUE +#define HSE_VALUE (8000000) +#endif + +#ifndef HSI_VALUE +#define HSI_VALUE (8000000) +#endif + +#ifndef HSI48_VALUE +#define HSI48_VALUE (48000000) +#endif + +/* This variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock there is no need to + call the 2 first functions listed above, since SystemCoreClock variable is + updated automatically. +*/ +uint32_t SystemCoreClock = 8000000; + +const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; + +void SystemInit(void) { + // Set HSION bit + RCC->CR |= (uint32_t)0x00000001U; + + #if defined(STM32F051x8) || defined(STM32F058x8) + // Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits + RCC->CFGR &= (uint32_t)0xF8FFB80CU; + #else + // Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits + RCC->CFGR &= (uint32_t)0x08FFB80CU; + #endif + + // Reset HSEON, CSSON and PLLON bits + RCC->CR &= (uint32_t)0xFEF6FFFFU; + + // Reset HSEBYP bit + RCC->CR &= (uint32_t)0xFFFBFFFFU; + + // Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits + RCC->CFGR &= (uint32_t)0xFFC0FFFFU; + + // Reset PREDIV[3:0] bits + RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U; + + #if defined(STM32F072xB) || defined(STM32F078xx) + // Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFCFE2CU; + #elif defined(STM32F071xB) + // Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFCEACU; + #elif defined(STM32F091xC) || defined(STM32F098xx) + // Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFF0FEACU; + #elif defined(STM32F030x6) || defined(STM32F030x8) || defined(STM32F031x6) || defined(STM32F038xx) || defined(STM32F030xC) + // Reset USART1SW[1:0], I2C1SW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFEECU; + #elif defined(STM32F051x8) || defined(STM32F058xx) + // Reset USART1SW[1:0], I2C1SW, CECSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFEACU; + #elif defined(STM32F042x6) || defined(STM32F048xx) + // Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFE2CU; + #elif defined(STM32F070x6) || defined(STM32F070xB) + // Reset USART1SW[1:0], I2C1SW, USBSW and ADCSW bits + RCC->CFGR3 &= (uint32_t)0xFFFFFE6CU; + // Set default USB clock to PLLCLK, since there is no HSI48 + RCC->CFGR3 |= (uint32_t)0x00000080U; + #else + #warning "No target selected" + #endif + + // Reset HSI14 bit + RCC->CR2 &= (uint32_t)0xFFFFFFFEU; + + // Disable all interrupts + RCC->CIR = 0x00000000U; + + // dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI + SCB->CCR |= SCB_CCR_STKALIGN_Msk; +} + +void SystemClock_Config(void) { + // Set flash latency to 1 because SYSCLK > 24MHz + FLASH->ACR = (FLASH->ACR & ~0x7) | 0x1; + + // Use the 48MHz internal oscillator + RCC->CR2 |= RCC_CR2_HSI48ON; + while ((RCC->CR2 & RCC_CR2_HSI48RDY) == 0) { + } + RCC->CFGR |= 3 << RCC_CFGR_SW_Pos; + while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != 0x03) { + // Wait for SYSCLK source to change + } + + SystemCoreClockUpdate(); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); +} + +void SystemCoreClockUpdate(void) { + // Get SYSCLK source + uint32_t tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) { + case RCC_CFGR_SWS_HSI: + SystemCoreClock = HSI_VALUE; + break; + case RCC_CFGR_SWS_HSE: + SystemCoreClock = HSE_VALUE; + break; + case RCC_CFGR_SWS_PLL: { + /* Get PLL clock source and multiplication factor */ + uint32_t pllmull = RCC->CFGR & RCC_CFGR_PLLMUL; + uint32_t pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + pllmull = (pllmull >> 18) + 2; + uint32_t predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1; + + if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV) { + /* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */ + SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull; + #if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) \ + || defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx) + } else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV) { + /* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */ + SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull; + #endif + } else { + #if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \ + || defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \ + || defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC) + /* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */ + SystemCoreClock = (HSI_VALUE / predivfactor) * pllmull; + #else + /* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + #endif + } + break; + } + case RCC_CFGR_SWS_HSI48: + SystemCoreClock = HSI48_VALUE; + break; + default: + SystemCoreClock = HSI_VALUE; + break; + } + + // Compute HCLK clock frequency + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + SystemCoreClock >>= tmp; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h index c1def50c29..256a500c27 100644 --- a/ports/stm32/systick.h +++ b/ports/stm32/systick.h @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_SYSTICK_H -#define MICROPY_INCLUDED_STMHAL_SYSTICK_H +#ifndef MICROPY_INCLUDED_STM32_SYSTICK_H +#define MICROPY_INCLUDED_STM32_SYSTICK_H void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms); bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms); -#endif // MICROPY_INCLUDED_STMHAL_SYSTICK_H +#endif // MICROPY_INCLUDED_STM32_SYSTICK_H diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 96a6baa02d..cf198e8651 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -162,14 +162,15 @@ void timer_deinit(void) { } } +#if defined(TIM5) // TIM5 is set-up for the servo controller // This function inits but does not start the timer void timer_tim5_init(void) { // TIM5 clock enable - __TIM5_CLK_ENABLE(); + __HAL_RCC_TIM5_CLK_ENABLE(); // set up and enable interrupt - HAL_NVIC_SetPriority(TIM5_IRQn, IRQ_PRI_TIM5, IRQ_SUBPRI_TIM5); + NVIC_SetPriority(TIM5_IRQn, IRQ_PRI_TIM5); HAL_NVIC_EnableIRQ(TIM5_IRQn); // PWM clock configuration @@ -181,6 +182,7 @@ void timer_tim5_init(void) { HAL_TIM_PWM_Init(&TIM5_Handle); } +#endif #if defined(TIM6) // Init TIM6 with a counter-overflow at the given frequency (given in Hz) @@ -188,7 +190,7 @@ void timer_tim5_init(void) { // This function inits but does not start the timer TIM_HandleTypeDef *timer_tim6_init(uint freq) { // TIM6 clock enable - __TIM6_CLK_ENABLE(); + __HAL_RCC_TIM6_CLK_ENABLE(); // Timer runs at SystemCoreClock / 2 // Compute the prescaler value so TIM6 triggers at freq-Hz @@ -226,19 +228,33 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { // APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its // respective APB clock. See DM00031020 Rev 4, page 115. uint32_t timer_get_source_freq(uint32_t tim_id) { - uint32_t source; + uint32_t source, clk_div; if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) { // TIM{1,8,9,10,11} are on APB2 + #if defined(STM32F0) + source = HAL_RCC_GetPCLK1Freq(); + clk_div = RCC->CFGR & RCC_CFGR_PPRE; + #elif defined(STM32H7) source = HAL_RCC_GetPCLK2Freq(); - if ((uint32_t)((RCC->CFGR & RCC_CFGR_PPRE2) >> 3) != RCC_HCLK_DIV1) { - source *= 2; - } + clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE2; + #else + source = HAL_RCC_GetPCLK2Freq(); + clk_div = RCC->CFGR & RCC_CFGR_PPRE2; + #endif } else { // TIM{2,3,4,5,6,7,12,13,14} are on APB1 source = HAL_RCC_GetPCLK1Freq(); - if ((uint32_t)(RCC->CFGR & RCC_CFGR_PPRE1) != RCC_HCLK_DIV1) { - source *= 2; - } + #if defined(STM32F0) + clk_div = RCC->CFGR & RCC_CFGR_PPRE; + #elif defined(STM32H7) + clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE1; + #else + clk_div = RCC->CFGR & RCC_CFGR_PPRE1; + #endif + } + if (clk_div != 0) { + // APB prescaler for this timer is > 1 + source *= 2; } return source; } @@ -302,7 +318,7 @@ STATIC uint32_t compute_prescaler_period_from_freq(pyb_timer_obj_t *self, mp_obj STATIC uint32_t compute_period(pyb_timer_obj_t *self) { // In center mode, compare == period corresponds to 100% // In edge mode, compare == (period + 1) corresponds to 100% - uint32_t period = (__HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self)); + uint32_t period = (__HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self)); if (period != 0xffffffff) { if (self->tim.Init.CounterMode == TIM_COUNTERMODE_UP || self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN) { @@ -439,7 +455,7 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ mp_printf(print, "Timer(%u)", self->tim_id); } else { uint32_t prescaler = self->tim.Instance->PSC & 0xffff; - uint32_t period = __HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self); + uint32_t period = __HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self); // for efficiency, we compute and print freq as an int (not a float) uint32_t freq = timer_get_source_freq(self->tim_id) / ((prescaler + 1) * (period + 1)); mp_printf(print, "Timer(%u, freq=%u, prescaler=%u, period=%u, mode=%s, div=%u", @@ -554,57 +570,61 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons // enable TIM clock switch (self->tim_id) { - case 1: __TIM1_CLK_ENABLE(); break; - case 2: __TIM2_CLK_ENABLE(); break; - case 3: __TIM3_CLK_ENABLE(); break; - case 4: __TIM4_CLK_ENABLE(); break; - case 5: __TIM5_CLK_ENABLE(); break; + case 1: __HAL_RCC_TIM1_CLK_ENABLE(); break; + case 2: __HAL_RCC_TIM2_CLK_ENABLE(); break; + case 3: __HAL_RCC_TIM3_CLK_ENABLE(); break; + #if defined(TIM4) + case 4: __HAL_RCC_TIM4_CLK_ENABLE(); break; + #endif + #if defined(TIM5) + case 5: __HAL_RCC_TIM5_CLK_ENABLE(); break; + #endif #if defined(TIM6) - case 6: __TIM6_CLK_ENABLE(); break; + case 6: __HAL_RCC_TIM6_CLK_ENABLE(); break; #endif #if defined(TIM7) - case 7: __TIM7_CLK_ENABLE(); break; + case 7: __HAL_RCC_TIM7_CLK_ENABLE(); break; #endif #if defined(TIM8) - case 8: __TIM8_CLK_ENABLE(); break; + case 8: __HAL_RCC_TIM8_CLK_ENABLE(); break; #endif #if defined(TIM9) - case 9: __TIM9_CLK_ENABLE(); break; + case 9: __HAL_RCC_TIM9_CLK_ENABLE(); break; #endif #if defined(TIM10) - case 10: __TIM10_CLK_ENABLE(); break; + case 10: __HAL_RCC_TIM10_CLK_ENABLE(); break; #endif #if defined(TIM11) - case 11: __TIM11_CLK_ENABLE(); break; + case 11: __HAL_RCC_TIM11_CLK_ENABLE(); break; #endif #if defined(TIM12) - case 12: __TIM12_CLK_ENABLE(); break; + case 12: __HAL_RCC_TIM12_CLK_ENABLE(); break; #endif #if defined(TIM13) - case 13: __TIM13_CLK_ENABLE(); break; + case 13: __HAL_RCC_TIM13_CLK_ENABLE(); break; #endif #if defined(TIM14) - case 14: __TIM14_CLK_ENABLE(); break; + case 14: __HAL_RCC_TIM14_CLK_ENABLE(); break; #endif #if defined(TIM15) - case 15: __TIM15_CLK_ENABLE(); break; + case 15: __HAL_RCC_TIM15_CLK_ENABLE(); break; #endif #if defined(TIM16) - case 16: __TIM16_CLK_ENABLE(); break; + case 16: __HAL_RCC_TIM16_CLK_ENABLE(); break; #endif #if defined(TIM17) - case 17: __TIM17_CLK_ENABLE(); break; + case 17: __HAL_RCC_TIM17_CLK_ENABLE(); break; #endif } // set IRQ priority (if not a special timer) if (self->tim_id != 5) { - HAL_NVIC_SetPriority(self->irqn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); + NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_TIMX); if (self->tim_id == 1) { - HAL_NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); + NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX); #if defined(TIM8) } else if (self->tim_id == 8) { - HAL_NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); + NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX); #endif } } @@ -635,19 +655,25 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons return mp_const_none; } -// This table encodes the timer instance and irq number. +// This table encodes the timer instance and irq number (for the update irq). // It assumes that timer instance pointer has the lower 8 bits cleared. #define TIM_ENTRY(id, irq) [id - 1] = (uint32_t)TIM##id | irq STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F0) + TIM_ENTRY(1, TIM1_BRK_UP_TRG_COM_IRQn), + #elif defined(STM32F4) || defined(STM32F7) TIM_ENTRY(1, TIM1_UP_TIM10_IRQn), - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) TIM_ENTRY(1, TIM1_UP_TIM16_IRQn), #endif TIM_ENTRY(2, TIM2_IRQn), TIM_ENTRY(3, TIM3_IRQn), + #if defined(TIM4) TIM_ENTRY(4, TIM4_IRQn), + #endif + #if defined(TIM5) TIM_ENTRY(5, TIM5_IRQn), + #endif #if defined(TIM6) TIM_ENTRY(6, TIM6_DAC_IRQn), #endif @@ -655,9 +681,9 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { TIM_ENTRY(7, TIM7_IRQn), #endif #if defined(TIM8) - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) TIM_ENTRY(8, TIM8_UP_TIM13_IRQn), - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) TIM_ENTRY(8, TIM8_UP_IRQn), #endif #endif @@ -676,18 +702,32 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { #if defined(TIM13) TIM_ENTRY(13, TIM8_UP_TIM13_IRQn), #endif - #if defined(TIM14) + #if defined(STM32F0) + TIM_ENTRY(14, TIM14_IRQn), + #elif defined(TIM14) TIM_ENTRY(14, TIM8_TRG_COM_TIM14_IRQn), #endif #if defined(TIM15) + #if defined(STM32F0) || defined(STM32H7) + TIM_ENTRY(15, TIM15_IRQn), + #else TIM_ENTRY(15, TIM1_BRK_TIM15_IRQn), #endif + #endif #if defined(TIM16) + #if defined(STM32F0) || defined(STM32H7) + TIM_ENTRY(16, TIM16_IRQn), + #else TIM_ENTRY(16, TIM1_UP_TIM16_IRQn), #endif + #endif #if defined(TIM17) + #if defined(STM32F0) || defined(STM32H7) + TIM_ENTRY(17, TIM17_IRQn), + #else TIM_ENTRY(17, TIM1_TRG_COM_TIM17_IRQn), #endif + #endif }; #undef TIM_ENTRY @@ -1049,8 +1089,12 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma if (self->tim.Instance != TIM1 && self->tim.Instance != TIM2 && self->tim.Instance != TIM3 + #if defined(TIM4) && self->tim.Instance != TIM4 + #endif + #if defined(TIM5) && self->tim.Instance != TIM5 + #endif #if defined(TIM8) && self->tim.Instance != TIM8 #endif @@ -1062,7 +1106,7 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma // an interrupt by initializing the timer. __HAL_TIM_DISABLE_IT(&self->tim, TIM_IT_UPDATE); HAL_TIM_Encoder_Init(&self->tim, &enc_config); - __HAL_TIM_SetCounter(&self->tim, 0); + __HAL_TIM_SET_COUNTER(&self->tim, 0); if (self->callback != mp_const_none) { __HAL_TIM_CLEAR_FLAG(&self->tim, TIM_IT_UPDATE); __HAL_TIM_ENABLE_IT(&self->tim, TIM_IT_UPDATE); @@ -1088,7 +1132,7 @@ STATIC mp_obj_t pyb_timer_counter(size_t n_args, const mp_obj_t *args) { return mp_obj_new_int(self->tim.Instance->CNT); } else { // set - __HAL_TIM_SetCounter(&self->tim, mp_obj_get_int(args[1])); + __HAL_TIM_SET_COUNTER(&self->tim, mp_obj_get_int(args[1])); return mp_const_none; } } @@ -1110,7 +1154,7 @@ STATIC mp_obj_t pyb_timer_freq(size_t n_args, const mp_obj_t *args) { if (n_args == 1) { // get uint32_t prescaler = self->tim.Instance->PSC & 0xffff; - uint32_t period = __HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self); + uint32_t period = __HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self); uint32_t source_freq = timer_get_source_freq(self->tim_id); uint32_t divide = ((prescaler + 1) * (period + 1)); #if MICROPY_PY_BUILTINS_FLOAT @@ -1126,7 +1170,7 @@ STATIC mp_obj_t pyb_timer_freq(size_t n_args, const mp_obj_t *args) { uint32_t period; uint32_t prescaler = compute_prescaler_period_from_freq(self, args[1], &period); self->tim.Instance->PSC = prescaler; - __HAL_TIM_SetAutoreload(&self->tim, period); + __HAL_TIM_SET_AUTORELOAD(&self->tim, period); return mp_const_none; } } @@ -1153,10 +1197,10 @@ STATIC mp_obj_t pyb_timer_period(size_t n_args, const mp_obj_t *args) { pyb_timer_obj_t *self = args[0]; if (n_args == 1) { // get - return mp_obj_new_int(__HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self)); + return mp_obj_new_int(__HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self)); } else { // set - __HAL_TIM_SetAutoreload(&self->tim, mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self)); + __HAL_TIM_SET_AUTORELOAD(&self->tim, mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self)); return mp_const_none; } } @@ -1265,10 +1309,10 @@ STATIC mp_obj_t pyb_timer_channel_capture_compare(size_t n_args, const mp_obj_t pyb_timer_channel_obj_t *self = args[0]; if (n_args == 1) { // get - return mp_obj_new_int(__HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer)); + return mp_obj_new_int(__HAL_TIM_GET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer)); } else { // set - __HAL_TIM_SetCompare(&self->timer->tim, TIMER_CHANNEL(self), mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self->timer)); + __HAL_TIM_SET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self), mp_obj_get_int(args[1]) & TIMER_CNT_MASK(self->timer)); return mp_const_none; } } @@ -1285,12 +1329,12 @@ STATIC mp_obj_t pyb_timer_channel_pulse_width_percent(size_t n_args, const mp_ob uint32_t period = compute_period(self->timer); if (n_args == 1) { // get - uint32_t cmp = __HAL_TIM_GetCompare(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer); + uint32_t cmp = __HAL_TIM_GET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self)) & TIMER_CNT_MASK(self->timer); return compute_percent_from_pwm_value(period, cmp); } else { // set uint32_t cmp = compute_pwm_value_from_percent(period, args[1]); - __HAL_TIM_SetCompare(&self->timer->tim, TIMER_CHANNEL(self), cmp & TIMER_CNT_MASK(self->timer)); + __HAL_TIM_SET_COMPARE(&self->timer->tim, TIMER_CHANNEL(self), cmp & TIMER_CNT_MASK(self->timer)); return mp_const_none; } } @@ -1365,7 +1409,7 @@ STATIC void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_o uint32_t irq_mask = TIMER_IRQ_MASK(channel); if (__HAL_TIM_GET_FLAG(&tim->tim, irq_mask) != RESET) { - if (__HAL_TIM_GET_ITSTATUS(&tim->tim, irq_mask) != RESET) { + if (__HAL_TIM_GET_IT_SOURCE(&tim->tim, irq_mask) != RESET) { // clear the interrupt __HAL_TIM_CLEAR_IT(&tim->tim, irq_mask); @@ -1427,7 +1471,7 @@ void timer_irq_handler(uint tim_id) { if (unhandled != 0) { __HAL_TIM_DISABLE_IT(&tim->tim, unhandled); __HAL_TIM_CLEAR_IT(&tim->tim, unhandled); - printf("Unhandled interrupt SR=0x%02lx (now disabled)\n", unhandled); + printf("Unhandled interrupt SR=0x%02x (now disabled)\n", (unsigned int)unhandled); } } } diff --git a/ports/stm32/timer.h b/ports/stm32/timer.h index 775accc3d4..2ba91cf158 100644 --- a/ports/stm32/timer.h +++ b/ports/stm32/timer.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_TIMER_H -#define MICROPY_INCLUDED_STMHAL_TIMER_H +#ifndef MICROPY_INCLUDED_STM32_TIMER_H +#define MICROPY_INCLUDED_STM32_TIMER_H extern TIM_HandleTypeDef TIM5_Handle; @@ -39,4 +39,4 @@ void timer_irq_handler(uint tim_id); TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer); -#endif // MICROPY_INCLUDED_STMHAL_TIMER_H +#endif // MICROPY_INCLUDED_STM32_TIMER_H diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 8f0513e8c9..5d3076ccde 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -34,9 +34,10 @@ #include "py/stream.h" #include "py/mperrno.h" #include "py/mphal.h" +#include "lib/utils/interrupt_char.h" #include "uart.h" #include "irq.h" -#include "genhdr/pins.h" +#include "pendsv.h" /// \moduleref pyb /// \class UART - duplex serial communication bus @@ -82,6 +83,7 @@ struct _pyb_uart_obj_t { IRQn_Type irqn; pyb_uart_t uart_id : 8; bool is_enabled : 1; + bool attached_to_repl; // whether the UART is attached to REPL byte char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars uint16_t char_mask; // 0x7f for 7 bit, 0xff for 8 bit, 0x1ff for 9 bit uint16_t timeout; // timeout waiting for first char @@ -93,8 +95,26 @@ struct _pyb_uart_obj_t { }; STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in); +extern void NORETURN __fatal_error(const char *msg); void uart_init0(void) { + #if defined(STM32H7) + RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit = {0}; + // Configure USART1/6 clock source + RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART16; + RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2; + if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } + + // Configure USART2/3/4/5/7/8 clock source + RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578; + RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1; + if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } + #endif + for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_uart_obj_all)); i++) { MP_STATE_PORT(pyb_uart_obj_all)[i] = NULL; } @@ -166,9 +186,9 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 1; UARTx = USART1; irqn = USART1_IRQn; - pins[0] = &MICROPY_HW_UART1_TX; - pins[1] = &MICROPY_HW_UART1_RX; - __USART1_CLK_ENABLE(); + pins[0] = MICROPY_HW_UART1_TX; + pins[1] = MICROPY_HW_UART1_RX; + __HAL_RCC_USART1_CLK_ENABLE(); break; #endif @@ -177,19 +197,19 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 2; UARTx = USART2; irqn = USART2_IRQn; - pins[0] = &MICROPY_HW_UART2_TX; - pins[1] = &MICROPY_HW_UART2_RX; + pins[0] = MICROPY_HW_UART2_TX; + pins[1] = MICROPY_HW_UART2_RX; #if defined(MICROPY_HW_UART2_RTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { - pins[2] = &MICROPY_HW_UART2_RTS; + pins[2] = MICROPY_HW_UART2_RTS; } #endif #if defined(MICROPY_HW_UART2_CTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { - pins[3] = &MICROPY_HW_UART2_CTS; + pins[3] = MICROPY_HW_UART2_CTS; } #endif - __USART2_CLK_ENABLE(); + __HAL_RCC_USART2_CLK_ENABLE(); break; #endif @@ -198,19 +218,19 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 3; UARTx = USART3; irqn = USART3_IRQn; - pins[0] = &MICROPY_HW_UART3_TX; - pins[1] = &MICROPY_HW_UART3_RX; + pins[0] = MICROPY_HW_UART3_TX; + pins[1] = MICROPY_HW_UART3_RX; #if defined(MICROPY_HW_UART3_RTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { - pins[2] = &MICROPY_HW_UART3_RTS; + pins[2] = MICROPY_HW_UART3_RTS; } #endif #if defined(MICROPY_HW_UART3_CTS) if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { - pins[3] = &MICROPY_HW_UART3_CTS; + pins[3] = MICROPY_HW_UART3_CTS; } #endif - __USART3_CLK_ENABLE(); + __HAL_RCC_USART3_CLK_ENABLE(); break; #endif @@ -219,9 +239,9 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 4; UARTx = UART4; irqn = UART4_IRQn; - pins[0] = &MICROPY_HW_UART4_TX; - pins[1] = &MICROPY_HW_UART4_RX; - __UART4_CLK_ENABLE(); + pins[0] = MICROPY_HW_UART4_TX; + pins[1] = MICROPY_HW_UART4_RX; + __HAL_RCC_UART4_CLK_ENABLE(); break; #endif @@ -230,9 +250,9 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 5; UARTx = UART5; irqn = UART5_IRQn; - pins[0] = &MICROPY_HW_UART5_TX; - pins[1] = &MICROPY_HW_UART5_RX; - __UART5_CLK_ENABLE(); + pins[0] = MICROPY_HW_UART5_TX; + pins[1] = MICROPY_HW_UART5_RX; + __HAL_RCC_UART5_CLK_ENABLE(); break; #endif @@ -241,9 +261,19 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 6; UARTx = USART6; irqn = USART6_IRQn; - pins[0] = &MICROPY_HW_UART6_TX; - pins[1] = &MICROPY_HW_UART6_RX; - __USART6_CLK_ENABLE(); + pins[0] = MICROPY_HW_UART6_TX; + pins[1] = MICROPY_HW_UART6_RX; + #if defined(MICROPY_HW_UART6_RTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_RTS) { + pins[2] = MICROPY_HW_UART6_RTS; + } + #endif + #if defined(MICROPY_HW_UART6_CTS) + if (uart_obj->uart.Init.HwFlowCtl & UART_HWCONTROL_CTS) { + pins[3] = MICROPY_HW_UART6_CTS; + } + #endif + __HAL_RCC_USART6_CLK_ENABLE(); break; #endif @@ -252,20 +282,26 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 7; UARTx = UART7; irqn = UART7_IRQn; - pins[0] = &MICROPY_HW_UART7_TX; - pins[1] = &MICROPY_HW_UART7_RX; - __UART7_CLK_ENABLE(); + pins[0] = MICROPY_HW_UART7_TX; + pins[1] = MICROPY_HW_UART7_RX; + __HAL_RCC_UART7_CLK_ENABLE(); break; #endif #if defined(MICROPY_HW_UART8_TX) && defined(MICROPY_HW_UART8_RX) case PYB_UART_8: uart_unit = 8; + #if defined(STM32F0) + UARTx = USART8; + irqn = USART3_8_IRQn; + __HAL_RCC_USART8_CLK_ENABLE(); + #else UARTx = UART8; irqn = UART8_IRQn; - pins[0] = &MICROPY_HW_UART8_TX; - pins[1] = &MICROPY_HW_UART8_RX; - __UART8_CLK_ENABLE(); + __HAL_RCC_UART8_CLK_ENABLE(); + #endif + pins[0] = MICROPY_HW_UART8_TX; + pins[1] = MICROPY_HW_UART8_RX; break; #endif @@ -293,10 +329,15 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { HAL_UART_Init(&uart_obj->uart); uart_obj->is_enabled = true; + uart_obj->attached_to_repl = false; return true; } +void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached) { + self->attached_to_repl = attached; +} + /* obsolete and unused bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate) { UART_HandleTypeDef *uh = &uart_obj->uart; @@ -357,7 +398,7 @@ int uart_rx_char(pyb_uart_obj_t *self) { return data; } else { // no buffering - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) return self->uart.Instance->RDR & self->char_mask; #else return self->uart.Instance->DR & self->char_mask; @@ -436,7 +477,7 @@ STATIC size_t uart_tx_data(pyb_uart_obj_t *self, const void *src_in, size_t num_ } else { data = *src++; } - #if defined(MCU_SERIES_F4) + #if defined(STM32F4) uart->DR = data; #else uart->TDR = data; @@ -475,12 +516,17 @@ void uart_irq_handler(mp_uint_t uart_id) { uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len; if (next_head != self->read_buf_tail) { // only read data if room in buf - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) int data = self->uart.Instance->RDR; // clears UART_FLAG_RXNE #else int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE #endif data &= self->char_mask; + // Handle interrupt coming in on a UART REPL + if (self->attached_to_repl && data == mp_interrupt_char) { + pendsv_kbd_intr(); + return; + } if (self->char_width == CHAR_WIDTH_9BIT) { ((uint16_t*)self->read_buf)[self->read_buf_head] = data; } else { @@ -502,7 +548,14 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k if (!self->is_enabled) { mp_printf(print, "UART(%u)", self->uart_id); } else { - mp_int_t bits = (self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9); + mp_int_t bits; + switch (self->uart.Init.WordLength) { + #ifdef UART_WORDLENGTH_7B + case UART_WORDLENGTH_7B: bits = 7; break; + #endif + case UART_WORDLENGTH_8B: bits = 8; break; + case UART_WORDLENGTH_9B: default: bits = 9; break; + } if (self->uart.Init.Parity != UART_PARITY_NONE) { bits -= 1; } @@ -582,6 +635,10 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const init->WordLength = UART_WORDLENGTH_8B; } else if (bits == 9) { init->WordLength = UART_WORDLENGTH_9B; + #ifdef UART_WORDLENGTH_7B + } else if (bits == 7) { + init->WordLength = UART_WORDLENGTH_7B; + #endif } else { mp_raise_ValueError("unsupported combination of bits and parity"); } @@ -642,22 +699,37 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const self->read_buf_len = args.read_buf_len.u_int + 1; // +1 to adjust for usable length of buffer self->read_buf = m_new(byte, self->read_buf_len << self->char_width); __HAL_UART_ENABLE_IT(&self->uart, UART_IT_RXNE); - HAL_NVIC_SetPriority(self->irqn, IRQ_PRI_UART, IRQ_SUBPRI_UART); + NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_UART); HAL_NVIC_EnableIRQ(self->irqn); } // compute actual baudrate that was configured // (this formula assumes UART_OVERSAMPLING_16) uint32_t actual_baudrate = 0; - #if defined(MCU_SERIES_F7) + #if defined(STM32F0) + actual_baudrate = HAL_RCC_GetPCLK1Freq(); + #elif defined(STM32F7) || defined(STM32H7) UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED; UART_GETCLOCKSOURCE(&self->uart, clocksource); switch (clocksource) { + #if defined(STM32H7) + case UART_CLOCKSOURCE_D2PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break; + case UART_CLOCKSOURCE_D3PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break; + case UART_CLOCKSOURCE_D2PCLK2: actual_baudrate = HAL_RCC_GetPCLK2Freq(); break; + #else case UART_CLOCKSOURCE_PCLK1: actual_baudrate = HAL_RCC_GetPCLK1Freq(); break; case UART_CLOCKSOURCE_PCLK2: actual_baudrate = HAL_RCC_GetPCLK2Freq(); break; - case UART_CLOCKSOURCE_HSI: actual_baudrate = HSI_VALUE; break; case UART_CLOCKSOURCE_SYSCLK: actual_baudrate = HAL_RCC_GetSysClockFreq(); break; + #endif + #if defined(STM32H7) + case UART_CLOCKSOURCE_CSI: actual_baudrate = CSI_VALUE; break; + #endif + case UART_CLOCKSOURCE_HSI: actual_baudrate = HSI_VALUE; break; case UART_CLOCKSOURCE_LSE: actual_baudrate = LSE_VALUE; break; + #if defined(STM32H7) + case UART_CLOCKSOURCE_PLL2: + case UART_CLOCKSOURCE_PLL3: + #endif case UART_CLOCKSOURCE_UNDEFINED: break; } #else @@ -782,55 +854,57 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { HAL_UART_DeInit(uart); if (uart->Instance == USART1) { HAL_NVIC_DisableIRQ(USART1_IRQn); - __USART1_FORCE_RESET(); - __USART1_RELEASE_RESET(); - __USART1_CLK_DISABLE(); + __HAL_RCC_USART1_FORCE_RESET(); + __HAL_RCC_USART1_RELEASE_RESET(); + __HAL_RCC_USART1_CLK_DISABLE(); } else if (uart->Instance == USART2) { HAL_NVIC_DisableIRQ(USART2_IRQn); - __USART2_FORCE_RESET(); - __USART2_RELEASE_RESET(); - __USART2_CLK_DISABLE(); + __HAL_RCC_USART2_FORCE_RESET(); + __HAL_RCC_USART2_RELEASE_RESET(); + __HAL_RCC_USART2_CLK_DISABLE(); #if defined(USART3) } else if (uart->Instance == USART3) { + #if !defined(STM32F0) HAL_NVIC_DisableIRQ(USART3_IRQn); - __USART3_FORCE_RESET(); - __USART3_RELEASE_RESET(); - __USART3_CLK_DISABLE(); + #endif + __HAL_RCC_USART3_FORCE_RESET(); + __HAL_RCC_USART3_RELEASE_RESET(); + __HAL_RCC_USART3_CLK_DISABLE(); #endif #if defined(UART4) } else if (uart->Instance == UART4) { HAL_NVIC_DisableIRQ(UART4_IRQn); - __UART4_FORCE_RESET(); - __UART4_RELEASE_RESET(); - __UART4_CLK_DISABLE(); + __HAL_RCC_UART4_FORCE_RESET(); + __HAL_RCC_UART4_RELEASE_RESET(); + __HAL_RCC_UART4_CLK_DISABLE(); #endif #if defined(UART5) } else if (uart->Instance == UART5) { HAL_NVIC_DisableIRQ(UART5_IRQn); - __UART5_FORCE_RESET(); - __UART5_RELEASE_RESET(); - __UART5_CLK_DISABLE(); + __HAL_RCC_UART5_FORCE_RESET(); + __HAL_RCC_UART5_RELEASE_RESET(); + __HAL_RCC_UART5_CLK_DISABLE(); #endif #if defined(UART6) } else if (uart->Instance == USART6) { HAL_NVIC_DisableIRQ(USART6_IRQn); - __USART6_FORCE_RESET(); - __USART6_RELEASE_RESET(); - __USART6_CLK_DISABLE(); + __HAL_RCC_USART6_FORCE_RESET(); + __HAL_RCC_USART6_RELEASE_RESET(); + __HAL_RCC_USART6_CLK_DISABLE(); #endif #if defined(UART7) } else if (uart->Instance == UART7) { HAL_NVIC_DisableIRQ(UART7_IRQn); - __UART7_FORCE_RESET(); - __UART7_RELEASE_RESET(); - __UART7_CLK_DISABLE(); + __HAL_RCC_UART7_FORCE_RESET(); + __HAL_RCC_UART7_RELEASE_RESET(); + __HAL_RCC_UART7_CLK_DISABLE(); #endif #if defined(UART8) } else if (uart->Instance == UART8) { HAL_NVIC_DisableIRQ(UART8_IRQn); - __UART8_FORCE_RESET(); - __UART8_RELEASE_RESET(); - __UART8_CLK_DISABLE(); + __HAL_RCC_UART8_FORCE_RESET(); + __HAL_RCC_UART8_RELEASE_RESET(); + __HAL_RCC_UART8_CLK_DISABLE(); #endif } return mp_const_none; @@ -887,7 +961,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar); // uart.sendbreak() STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) { pyb_uart_obj_t *self = self_in; - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) + #if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7) self->uart.Instance->RQR = USART_RQR_SBKRQ; // write-only register #else self->uart.Instance->CR1 |= USART_CR1_SBK; diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h index d176520a1b..4ab18ff225 100644 --- a/ports/stm32/uart.h +++ b/ports/stm32/uart.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_UART_H -#define MICROPY_INCLUDED_STMHAL_UART_H +#ifndef MICROPY_INCLUDED_STM32_UART_H +#define MICROPY_INCLUDED_STM32_UART_H typedef enum { PYB_UART_NONE = 0, @@ -45,8 +45,9 @@ void uart_init0(void); void uart_deinit(void); void uart_irq_handler(mp_uint_t uart_id); +void uart_attach_to_repl(pyb_uart_obj_t *self, bool attached); mp_uint_t uart_rx_any(pyb_uart_obj_t *uart_obj); int uart_rx_char(pyb_uart_obj_t *uart_obj); void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); -#endif // MICROPY_INCLUDED_STMHAL_UART_H +#endif // MICROPY_INCLUDED_STM32_UART_H diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 5017bb9303..c6fc86e05d 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -43,12 +43,17 @@ #include "bufhelper.h" #include "usb.h" -#if defined(USE_USB_FS) -#define USB_PHY_ID USB_PHY_FS_ID -#elif defined(USE_USB_HS) && defined(USE_USB_HS_IN_FS) -#define USB_PHY_ID USB_PHY_HS_ID +#if MICROPY_HW_ENABLE_USB + +// Work out which USB device to use as the main one (the one with the REPL) +#if !defined(MICROPY_HW_USB_MAIN_DEV) +#if defined(MICROPY_HW_USB_FS) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_FS_ID) +#elif defined(MICROPY_HW_USB_HS) && defined(MICROPY_HW_USB_HS_IN_FS) +#define MICROPY_HW_USB_MAIN_DEV (USB_PHY_HS_ID) #else -#error Unable to determine proper USB_PHY_ID to use +#error Unable to determine proper MICROPY_HW_USB_MAIN_DEV to use +#endif #endif // this will be persistent across a soft-reset @@ -59,13 +64,14 @@ typedef struct _usb_device_t { USBD_HandleTypeDef hUSBDDevice; usbd_cdc_msc_hid_state_t usbd_cdc_msc_hid_state; usbd_cdc_itf_t usbd_cdc_itf; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_itf_t usbd_cdc2_itf; + #endif usbd_hid_itf_t usbd_hid_itf; } usb_device_t; -#ifdef USE_DEVICE_MODE usb_device_t usb_device; pyb_usb_storage_medium_t pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_NONE; -#endif // predefined hid mouse data STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = { @@ -111,28 +117,32 @@ void pyb_usb_init0(void) { } bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { -#ifdef USE_DEVICE_MODE + bool high_speed = (mode & USBD_MODE_HIGH_SPEED) != 0; + mode &= 0x7f; usb_device_t *usb_dev = &usb_device; if (!usb_dev->enabled) { // only init USB once in the device's power-lifetime + // set up the USBD state + USBD_HandleTypeDef *usbd = &usb_dev->hUSBDDevice; + usbd->id = MICROPY_HW_USB_MAIN_DEV; + usbd->dev_state = USBD_STATE_DEFAULT; + usbd->pDesc = (USBD_DescriptorsTypeDef*)&USBD_Descriptors; + usbd->pClass = &USBD_CDC_MSC_HID; + usb_dev->usbd_cdc_msc_hid_state.pdev = usbd; + usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf.base; + #if MICROPY_HW_USB_ENABLE_CDC2 + usb_dev->usbd_cdc_msc_hid_state.cdc2 = &usb_dev->usbd_cdc2_itf.base; + #endif + usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf.base; + usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state; + // configure the VID, PID and the USBD mode (interfaces it will expose) USBD_SetVIDPIDRelease(&usb_dev->usbd_cdc_msc_hid_state, vid, pid, 0x0200, mode == USBD_MODE_CDC); if (USBD_SelectMode(&usb_dev->usbd_cdc_msc_hid_state, mode, hid_info) != 0) { return false; } - // set up the USBD state - USBD_HandleTypeDef *usbd = &usb_dev->hUSBDDevice; - usbd->id = USB_PHY_ID; - usbd->dev_state = USBD_STATE_DEFAULT; - usbd->pDesc = (USBD_DescriptorsTypeDef*)&USBD_Descriptors; - usbd->pClass = &USBD_CDC_MSC_HID; - usb_dev->usbd_cdc_msc_hid_state.pdev = usbd; - usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf; - usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf; - usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state; - switch (pyb_usb_storage_medium) { #if MICROPY_HW_HAS_SDCARD case PYB_USB_STORAGE_MEDIUM_SDCARD: @@ -145,11 +155,10 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H } // start the USB device - USBD_LL_Init(usbd); + USBD_LL_Init(usbd, high_speed); USBD_LL_Start(usbd); usb_dev->enabled = true; } -#endif return true; } @@ -171,11 +180,18 @@ int usb_vcp_recv_byte(uint8_t *c) { } void usb_vcp_send_strn(const char *str, int len) { -#ifdef USE_DEVICE_MODE if (usb_device.enabled) { usbd_cdc_tx_always(&usb_device.usbd_cdc_itf, (const uint8_t*)str, len); } -#endif +} + +usbd_cdc_itf_t *usb_vcp_get(int idx) { + #if MICROPY_HW_USB_ENABLE_CDC2 + if (idx == 1) { + return &usb_device.usbd_cdc2_itf; + } + #endif + return &usb_device.usbd_cdc_itf; } /******************************************************************************/ @@ -213,13 +229,16 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * { MP_QSTR_vid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = USBD_VID} }, { MP_QSTR_pid, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_hid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = (mp_obj_t)&pyb_usb_hid_mouse_obj} }, + #if USBD_SUPPORT_HS_MODE + { MP_QSTR_high_speed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + #endif }; // fetch the current usb mode -> pyb.usb_mode() if (n_args == 0) { #if defined(USE_HOST_MODE) return MP_OBJ_NEW_QSTR(MP_QSTR_host); - #elif defined(USE_DEVICE_MODE) + #else uint8_t mode = USBD_GetMode(&usb_device.usbd_cdc_msc_hid_state); switch (mode) { case USBD_MODE_CDC: @@ -250,9 +269,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // check if user wants to disable the USB if (args[0].u_obj == mp_const_none) { // disable usb - #if defined(USE_DEVICE_MODE) pyb_usb_dev_deinit(); - #endif return mp_const_none; } @@ -269,7 +286,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * goto bad_mode; } -#elif defined(USE_DEVICE_MODE) +#else // hardware configured for USB device mode @@ -284,6 +301,13 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pid = USBD_PID_CDC_MSC; } mode = USBD_MODE_CDC_MSC; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_CDC2_MSC; + } + mode = USBD_MODE_CDC2_MSC; + #endif } else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) { if (args[2].u_int == -1) { pid = USBD_PID_CDC_HID; @@ -294,6 +318,11 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * pid = USBD_PID_CDC; } mode = USBD_MODE_CDC; + } else if (strcmp(mode_str, "MSC") == 0) { + if (args[2].u_int == -1) { + pid = USBD_PID_MSC; + } + mode = USBD_MODE_MSC; } else { goto bad_mode; } @@ -316,14 +345,17 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * MP_STATE_PORT(pyb_hid_report_desc) = items[4]; } + #if USBD_SUPPORT_HS_MODE + if (args[4].u_bool) { + mode |= USBD_MODE_HIGH_SPEED; + } + #endif + // init the USB device if (!pyb_usb_dev_init(vid, pid, mode, &hid_info)) { goto bad_mode; } -#else - // hardware not configured for USB - goto bad_mode; #endif return mp_const_none; @@ -345,25 +377,37 @@ MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj, 0, pyb_usb_mode); typedef struct _pyb_usb_vcp_obj_t { mp_obj_base_t base; - usb_device_t *usb_dev; + usbd_cdc_itf_t *cdc_itf; } pyb_usb_vcp_obj_t; -STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device}; +STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf}; +#if MICROPY_HW_USB_ENABLE_CDC2 +STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp2_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc2_itf}; +#endif STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - mp_print_str(print, "USB_VCP()"); + int id = ((pyb_usb_vcp_obj_t*)self_in)->cdc_itf - &usb_device.usbd_cdc_itf; + mp_printf(print, "USB_VCP(%u)", id); } /// \classmethod \constructor() /// Create a new USB_VCP object. STATIC mp_obj_t pyb_usb_vcp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { // check arguments - mp_arg_check_num(n_args, n_kw, 0, 0, false); + mp_arg_check_num(n_args, n_kw, 0, 1, false); // TODO raise exception if USB is not configured for VCP - // return the USB VCP object - return (mp_obj_t)&pyb_usb_vcp_obj; + int id = (n_args == 0) ? 0 : mp_obj_get_int(args[0]); + if (id == 0) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj); + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if (id == 1) { + return MP_OBJ_FROM_PTR(&pyb_usb_vcp2_obj); + #endif + } else { + mp_raise_ValueError(NULL); + } } STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) { @@ -374,13 +418,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_usb_vcp_setinterrupt_obj, pyb_usb_vcp_setin STATIC mp_obj_t pyb_usb_vcp_isconnected(mp_obj_t self_in) { pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(usbd_cdc_is_connected(&self->usb_dev->usbd_cdc_itf)); + return mp_obj_new_bool(usbd_cdc_is_connected(self->cdc_itf)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_vcp_isconnected_obj, pyb_usb_vcp_isconnected); // deprecated in favour of USB_VCP.isconnected STATIC mp_obj_t pyb_have_cdc(void) { - return pyb_usb_vcp_isconnected(MP_OBJ_NULL); + return pyb_usb_vcp_isconnected(MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj)); } MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); @@ -388,7 +432,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); /// Return `True` if any characters waiting, else `False`. STATIC mp_obj_t pyb_usb_vcp_any(mp_obj_t self_in) { pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (usbd_cdc_rx_num(&self->usb_dev->usbd_cdc_itf) > 0) { + if (usbd_cdc_rx_num(self->cdc_itf) > 0) { return mp_const_true; } else { return mp_const_false; @@ -421,7 +465,7 @@ STATIC mp_obj_t pyb_usb_vcp_send(size_t n_args, const mp_obj_t *args, mp_map_t * pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data); // send the data - int ret = usbd_cdc_tx(&self->usb_dev->usbd_cdc_itf, bufinfo.buf, bufinfo.len, vals[1].u_int); + int ret = usbd_cdc_tx(self->cdc_itf, bufinfo.buf, bufinfo.len, vals[1].u_int); return mp_obj_new_int(ret); } @@ -448,7 +492,7 @@ STATIC mp_obj_t pyb_usb_vcp_recv(size_t n_args, const mp_obj_t *args, mp_map_t * mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr); // receive the data - int ret = usbd_cdc_rx(&self->usb_dev->usbd_cdc_itf, (uint8_t*)vstr.buf, vstr.len, vals[1].u_int); + int ret = usbd_cdc_rx(self->cdc_itf, (uint8_t*)vstr.buf, vstr.len, vals[1].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { @@ -486,7 +530,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_usb_vcp_locals_dict, pyb_usb_vcp_locals_dict_tab STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); - int ret = usbd_cdc_rx(&self->usb_dev->usbd_cdc_itf, (byte*)buf, size, 0); + int ret = usbd_cdc_rx(self->cdc_itf, (byte*)buf, size, 0); if (ret == 0) { // return EAGAIN error to indicate non-blocking *errcode = MP_EAGAIN; @@ -497,7 +541,7 @@ STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, i STATIC mp_uint_t pyb_usb_vcp_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); - int ret = usbd_cdc_tx(&self->usb_dev->usbd_cdc_itf, (const byte*)buf, size, 0); + int ret = usbd_cdc_tx(self->cdc_itf, (const byte*)buf, size, 0); if (ret == 0) { // return EAGAIN error to indicate non-blocking *errcode = MP_EAGAIN; @@ -512,10 +556,10 @@ STATIC mp_uint_t pyb_usb_vcp_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_ if (request == MP_STREAM_POLL) { mp_uint_t flags = arg; ret = 0; - if ((flags & MP_STREAM_POLL_RD) && usbd_cdc_rx_num(&self->usb_dev->usbd_cdc_itf) > 0) { + if ((flags & MP_STREAM_POLL_RD) && usbd_cdc_rx_num(self->cdc_itf) > 0) { ret |= MP_STREAM_POLL_RD; } - if ((flags & MP_STREAM_POLL_WR) && usbd_cdc_tx_half_empty(&self->usb_dev->usbd_cdc_itf)) { + if ((flags & MP_STREAM_POLL_WR) && usbd_cdc_tx_half_empty(self->cdc_itf)) { ret |= MP_STREAM_POLL_WR; } } else { @@ -579,7 +623,7 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t * }; // parse args - pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(args[0]); + pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(args[0]); mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); @@ -601,8 +645,7 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t * STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_hid_recv_obj, 1, pyb_usb_hid_recv); STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { -#ifdef USE_DEVICE_MODE - pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); + pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; byte temp_buf[8]; // get the buffer to send from @@ -620,12 +663,11 @@ STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { } // send the data - if (USBD_OK == USBD_HID_SendReport(&self->usb_dev->usbd_cdc_msc_hid_state, bufinfo.buf, bufinfo.len)) { + if (USBD_OK == USBD_HID_SendReport(&self->usb_dev->usbd_hid_itf.base, bufinfo.buf, bufinfo.len)) { return mp_obj_new_int(bufinfo.len); } else { return mp_obj_new_int(0); } -#endif return mp_const_none; } @@ -645,7 +687,7 @@ STATIC const mp_rom_map_elem_t pyb_usb_hid_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(pyb_usb_hid_locals_dict, pyb_usb_hid_locals_dict_table); STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { - pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); + pyb_usb_hid_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { mp_uint_t flags = arg; @@ -653,7 +695,7 @@ STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_ if ((flags & MP_STREAM_POLL_RD) && usbd_hid_rx_num(&self->usb_dev->usbd_hid_itf) > 0) { ret |= MP_STREAM_POLL_RD; } - if ((flags & MP_STREAM_POLL_WR) && USBD_HID_CanSendReport(&self->usb_dev->usbd_cdc_msc_hid_state)) { + if ((flags & MP_STREAM_POLL_WR) && USBD_HID_CanSendReport(&self->usb_dev->usbd_hid_itf.base)) { ret |= MP_STREAM_POLL_WR; } } else { @@ -739,3 +781,5 @@ void USR_KEYBRD_ProcessData(uint8_t pbuf) { } #endif // USE_HOST_MODE + +#endif // MICROPY_HW_ENABLE_USB diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h index 41c461fb2f..1de9e5d0e5 100644 --- a/ports/stm32/usb.h +++ b/ports/stm32/usb.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USB_H -#define MICROPY_INCLUDED_STMHAL_USB_H +#ifndef MICROPY_INCLUDED_STM32_USB_H +#define MICROPY_INCLUDED_STM32_USB_H #include "usbd_cdc_msc_hid0.h" @@ -35,6 +35,8 @@ #define USBD_PID_CDC_MSC (0x9800) #define USBD_PID_CDC_HID (0x9801) #define USBD_PID_CDC (0x9802) +#define USBD_PID_MSC (0x9803) +#define USBD_PID_CDC2_MSC (0x9804) typedef enum { PYB_USB_STORAGE_MEDIUM_NONE = 0, @@ -68,4 +70,4 @@ void pyb_usb_host_init(void); void pyb_usb_host_process(void); uint pyb_usb_host_get_keyboard(void); -#endif // MICROPY_INCLUDED_STMHAL_USB_H +#endif // MICROPY_INCLUDED_STM32_USB_H diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 2e9fba917c..91ae81bb32 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -45,6 +45,8 @@ #include "lib/utils/interrupt_char.h" #include "irq.h" +#if MICROPY_HW_ENABLE_USB + // CDC control commands #define CDC_SEND_ENCAPSULATED_COMMAND 0x00 #define CDC_GET_ENCAPSULATED_RESPONSE 0x01 @@ -56,9 +58,8 @@ #define CDC_SET_CONTROL_LINE_STATE 0x22 #define CDC_SEND_BREAK 0x23 -uint8_t *usbd_cdc_init(usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd) { - // Link the parent state - cdc->usbd = usbd; +uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; // Reset all the CDC state // Note: we don't reset tx_buf_ptr_in in order to allow the output buffer to @@ -70,6 +71,11 @@ uint8_t *usbd_cdc_init(usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd) { cdc->tx_buf_ptr_wait_count = 0; cdc->tx_need_empty_packet = 0; cdc->dev_is_connected = 0; + #if MICROPY_HW_USB_ENABLE_CDC2 + cdc->attached_to_repl = &cdc->base == cdc->base.usbd->cdc; + #else + cdc->attached_to_repl = 1; + #endif // Return the buffer to place the first USB OUT packet return cdc->rx_packet_buf; @@ -80,7 +86,9 @@ uint8_t *usbd_cdc_init(usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd) { // pbuf: buffer containing command data (request parameters) // length: number of data to be sent (in bytes) // Returns USBD_OK if all operations are OK else USBD_FAIL -int8_t usbd_cdc_control(usbd_cdc_itf_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length) { +int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, uint16_t length) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; + switch (cmd) { case CDC_SEND_ENCAPSULATED_COMMAND: /* Add your code here */ @@ -142,10 +150,7 @@ int8_t usbd_cdc_control(usbd_cdc_itf_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_ // This function is called to process outgoing data. We hook directly into the // SOF (start of frame) callback so that it is called exactly at the time it is // needed (reducing latency), and often enough (increasing bandwidth). -void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { - usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; - usbd_cdc_itf_t *cdc = usbd->cdc; - +static void usbd_cdc_sof(PCD_HandleTypeDef *hpcd, usbd_cdc_itf_t *cdc) { if (cdc == NULL || !cdc->dev_is_connected) { // CDC device is not connected to a host, so we are unable to send any data return; @@ -164,7 +169,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { // doing other things and we must give it a chance to read our data. if (cdc->tx_buf_ptr_wait_count < 500) { USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; - if (USBx_INEP(CDC_IN_EP & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) { + if (USBx_INEP(cdc->base.in_ep & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) { // USB in-endpoint is still reading the data cdc->tx_buf_ptr_wait_count++; return; @@ -185,7 +190,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { buffptr = cdc->tx_buf_ptr_out_shadow; - if (USBD_CDC_TransmitPacket(cdc->usbd, buffsize, &cdc->tx_buf[buffptr]) == USBD_OK) { + if (USBD_CDC_TransmitPacket(&cdc->base, buffsize, &cdc->tx_buf[buffptr]) == USBD_OK) { cdc->tx_buf_ptr_out_shadow += buffsize; if (cdc->tx_buf_ptr_out_shadow == USBD_CDC_TX_DATA_SIZE) { cdc->tx_buf_ptr_out_shadow = 0; @@ -198,18 +203,28 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { // the host waits for all data to arrive (ie, waits for a packet < max packet size). // To flush a packet of exactly max packet size, we need to send a zero-size packet. // See eg http://www.cypress.com/?id=4&rID=92719 - cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % CDC_DATA_FS_MAX_PACKET_SIZE == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); + cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(cdc->base.usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); } } } +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { + usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData; + usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc); + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc2); + #endif +} + // Data received over USB OUT endpoint is processed here. // len: number of bytes received into the buffer we passed to USBD_CDC_ReceivePacket // Returns USBD_OK if all operations are OK else USBD_FAIL -int8_t usbd_cdc_receive(usbd_cdc_itf_t *cdc, size_t len) { +int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) { + usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)cdc_in; + // copy the incoming data into the circular buffer for (const uint8_t *src = cdc->rx_packet_buf, *top = cdc->rx_packet_buf + len; src < top; ++src) { - if (mp_interrupt_char != -1 && *src == mp_interrupt_char) { + if (cdc->attached_to_repl && mp_interrupt_char != -1 && *src == mp_interrupt_char) { pendsv_kbd_intr(); } else { uint16_t next_put = (cdc->rx_buf_put + 1) & (USBD_CDC_RX_DATA_SIZE - 1); @@ -223,7 +238,7 @@ int8_t usbd_cdc_receive(usbd_cdc_itf_t *cdc, size_t len) { } // initiate next USB packet transfer - USBD_CDC_ReceivePacket(cdc->usbd, cdc->rx_packet_buf); + USBD_CDC_ReceivePacket(&cdc->base, cdc->rx_packet_buf); return USBD_OK; } @@ -347,3 +362,5 @@ int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeou // Success, return number of bytes read return len; } + +#endif diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index 98b8fc077d..cdf556d4ec 100644 --- a/ports/stm32/usbd_cdc_interface.h +++ b/ports/stm32/usbd_cdc_interface.h @@ -1,8 +1,8 @@ /* * This file is part of the MicroPython project, http://micropython.org/ */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H -#define MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H +#ifndef MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H +#define MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H /** ****************************************************************************** @@ -35,9 +35,9 @@ #define USBD_CDC_TX_DATA_SIZE (1024) // I think this can be any value (was 2048) typedef struct _usbd_cdc_itf_t { - usbd_cdc_msc_hid_state_t *usbd; // the parent USB device + usbd_cdc_state_t base; // state for the base CDC layer - uint8_t rx_packet_buf[CDC_DATA_FS_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer + uint8_t rx_packet_buf[CDC_DATA_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer uint8_t rx_user_buf[USBD_CDC_RX_DATA_SIZE]; // received data is buffered here until the user reads it volatile uint16_t rx_buf_put; // circular buffer index uint16_t rx_buf_get; // circular buffer index @@ -50,8 +50,12 @@ typedef struct _usbd_cdc_itf_t { uint8_t tx_need_empty_packet; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size volatile uint8_t dev_is_connected; // indicates if we are connected + uint8_t attached_to_repl; // indicates if interface is connected to REPL } usbd_cdc_itf_t; +// This is implemented in usb.c +usbd_cdc_itf_t *usb_vcp_get(int idx); + static inline int usbd_cdc_is_connected(usbd_cdc_itf_t *cdc) { return cdc->dev_is_connected; } @@ -63,4 +67,4 @@ void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len); int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc); int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeout); -#endif // MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H +#endif // MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index d39144851f..41a8353047 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -1,689 +1,670 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - */ - -/** - ****************************************************************************** - * @file USB_Device/CDC_Standalone/Src/usbd_conf.c - * @author MCD Application Team - * @version V1.0.1 - * @date 26-February-2014 - * @brief This file implements the USB Device library callbacks and MSP - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2014 STMicroelectronics

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

© COPYRIGHT(c) 2014 STMicroelectronics

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

© COPYRIGHT(c) 2014 STMicroelectronics

- * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __USBD_CONF_H -#define __USBD_CONF_H - -/* Includes ------------------------------------------------------------------*/ -#include -#include -#include - -#include "py/mpconfig.h" - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Common Config */ -#define USBD_MAX_NUM_INTERFACES 1 -#define USBD_MAX_NUM_CONFIGURATION 1 -#define USBD_MAX_STR_DESC_SIZ 0x100 -#define USBD_SUPPORT_USER_STRING 0 -#define USBD_SELF_POWERED 0 -#define USBD_DEBUG_LEVEL 0 - -/* Exported macro ------------------------------------------------------------*/ -/* Memory management macros */ -/* -these should not be used because the GC is reset on a soft reset but the usb is not -#include "gc.h" -#define USBD_malloc gc_alloc -#define USBD_free gc_free -#define USBD_memset memset -#define USBD_memcpy memcpy -*/ - -/* DEBUG macros */ -#if (USBD_DEBUG_LEVEL > 0) -#define USBD_UsrLog(...) printf(__VA_ARGS__);\ - printf("\n"); -#else -#define USBD_UsrLog(...) -#endif - -#if (USBD_DEBUG_LEVEL > 1) - -#define USBD_ErrLog(...) printf("ERROR: ") ;\ - printf(__VA_ARGS__);\ - printf("\n"); -#else -#define USBD_ErrLog(...) -#endif - -#if (USBD_DEBUG_LEVEL > 2) -#define USBD_DbgLog(...) printf("DEBUG : ") ;\ - printf(__VA_ARGS__);\ - printf("\n"); -#else -#define USBD_DbgLog(...) -#endif - -/* Exported functions ------------------------------------------------------- */ - -#endif /* __USBD_CONF_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/* + * This file is part of the MicroPython project, http://micropython.org/ + */ + +/** + ****************************************************************************** + * @file USB_Device/CDC_Standalone/Inc/usbd_conf.h + * @author MCD Application Team + * @version V1.0.1 + * @date 26-February-2014 + * @brief General low level driver configuration + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +#ifndef MICROPY_INCLUDED_STM32_USBD_CONF_H +#define MICROPY_INCLUDED_STM32_USBD_CONF_H + +#include +#include +#include +#include + +#define USBD_MAX_NUM_INTERFACES 4 +#define USBD_MAX_NUM_CONFIGURATION 1 +#define USBD_MAX_STR_DESC_SIZ 0x100 +#define USBD_SELF_POWERED 0 +#define USBD_DEBUG_LEVEL 0 + +#endif // MICROPY_INCLUDED_STM32_USBD_CONF_H + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbd_desc.c b/ports/stm32/usbd_desc.c index 1de75aee0f..4babebf640 100644 --- a/ports/stm32/usbd_desc.c +++ b/ports/stm32/usbd_desc.c @@ -33,8 +33,7 @@ #include "usbd_desc.h" #include "usbd_conf.h" -// need these headers just for MP_HAL_UNIQUE_ID_ADDRESS -#include "py/misc.h" +// need this header just for MP_HAL_UNIQUE_ID_ADDRESS #include "py/mphal.h" // So we don't clash with existing ST boards, we use the unofficial FOSS VID. @@ -104,115 +103,82 @@ STATIC uint8_t *USBD_DeviceDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length } /** - * @brief Returns the LangID string descriptor. - * @param speed: Current device speed + * @brief Returns a string descriptor + * @param idx: Index of the string descriptor to retrieve * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer + * @retval Pointer to descriptor buffer, or NULL if idx is invalid */ -STATIC uint8_t *USBD_LangIDStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - *length = sizeof(USBD_LangIDDesc); - return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf -} +STATIC uint8_t *USBD_StrDescriptor(USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length) { + char str_buf[16]; + const char *str = NULL; -/** - * @brief Returns the product string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_ProductStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - if (pdev->dev_speed == USBD_SPEED_HIGH) { - USBD_GetString((uint8_t *)USBD_PRODUCT_HS_STRING, str_desc, length); - } else { - USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, str_desc, length); + switch (idx) { + case USBD_IDX_LANGID_STR: + *length = sizeof(USBD_LangIDDesc); + return (uint8_t*)USBD_LangIDDesc; // the data should only be read from this buf + + case USBD_IDX_MFC_STR: + str = USBD_MANUFACTURER_STRING; + break; + + case USBD_IDX_PRODUCT_STR: + if (pdev->dev_speed == USBD_SPEED_HIGH) { + str = USBD_PRODUCT_HS_STRING; + } else { + str = USBD_PRODUCT_FS_STRING; + } + break; + + case USBD_IDX_SERIAL_STR: { + // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf + // says that the serial number has to be at least 12 digits long and that + // the last 12 digits need to be unique. It also stipulates that the valid + // character set is that of upper-case hexadecimal digits. + // + // The onboard DFU bootloader produces a 12-digit serial number based on + // the 96-bit unique ID, so for consistency we go with this algorithm. + // You can see the serial number if you use: lsusb -v + // + // See: https://my.st.com/52d187b7 for the algorithim used. + + uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS; + snprintf(str_buf, sizeof(str_buf), + "%02X%02X%02X%02X%02X%02X", + id[11], id[10] + id[2], id[9], id[8] + id[0], id[7], id[6]); + + str = str_buf; + break; + } + + case USBD_IDX_CONFIG_STR: + if (pdev->dev_speed == USBD_SPEED_HIGH) { + str = USBD_CONFIGURATION_HS_STRING; + } else { + str = USBD_CONFIGURATION_FS_STRING; + } + break; + + case USBD_IDX_INTERFACE_STR: + if (pdev->dev_speed == USBD_SPEED_HIGH) { + str = USBD_INTERFACE_HS_STRING; + } else { + str = USBD_INTERFACE_FS_STRING; + } + break; + + default: + // invalid string index + return NULL; } - return str_desc; -} - -/** - * @brief Returns the manufacturer string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_ManufacturerStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, str_desc, length); - return str_desc; -} - -/** - * @brief Returns the serial number string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_SerialStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - // This document: http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf - // says that the serial number has to be at least 12 digits long and that - // the last 12 digits need to be unique. It also stipulates that the valid - // character set is that of upper-case hexadecimal digits. - // - // The onboard DFU bootloader produces a 12-digit serial number based on - // the 96-bit unique ID, so for consistency we go with this algorithm. - // You can see the serial number if you do: - // - // dfu-util -l - // - // See: https://my.st.com/52d187b7 for the algorithim used. - - uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS; - char serial_buf[16]; - snprintf(serial_buf, sizeof(serial_buf), - "%02X%02X%02X%02X%02X%02X", - id[11], id[10] + id[2], id[9], id[8] + id[0], id[7], id[6]); uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - USBD_GetString((uint8_t *)serial_buf, str_desc, length); - return str_desc; -} - -/** - * @brief Returns the configuration string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_ConfigStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - if (pdev->dev_speed == USBD_SPEED_HIGH) { - USBD_GetString((uint8_t *)USBD_CONFIGURATION_HS_STRING, str_desc, length); - } else { - USBD_GetString((uint8_t *)USBD_CONFIGURATION_FS_STRING, str_desc, length); - } - return str_desc; -} - -/** - * @brief Returns the interface string descriptor. - * @param speed: Current device speed - * @param length: Pointer to data length variable - * @retval Pointer to descriptor buffer - */ -STATIC uint8_t *USBD_InterfaceStrDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - uint8_t *str_desc = ((usbd_cdc_msc_hid_state_t*)pdev->pClassData)->usbd_str_desc; - if (pdev->dev_speed == USBD_SPEED_HIGH) { - USBD_GetString((uint8_t *)USBD_INTERFACE_HS_STRING, str_desc, length); - } else { - USBD_GetString((uint8_t *)USBD_INTERFACE_FS_STRING, str_desc, length); - } + USBD_GetString((uint8_t*)str, str_desc, length); return str_desc; } const USBD_DescriptorsTypeDef USBD_Descriptors = { USBD_DeviceDescriptor, - USBD_LangIDStrDescriptor, - USBD_ManufacturerStrDescriptor, - USBD_ProductStrDescriptor, - USBD_SerialStrDescriptor, - USBD_ConfigStrDescriptor, - USBD_InterfaceStrDescriptor, + USBD_StrDescriptor, }; /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/usbd_desc.h b/ports/stm32/usbd_desc.h index a4de6c6819..0307defa5b 100644 --- a/ports/stm32/usbd_desc.h +++ b/ports/stm32/usbd_desc.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_DESC_H -#define MICROPY_INCLUDED_STMHAL_USBD_DESC_H +#ifndef MICROPY_INCLUDED_STM32_USBD_DESC_H +#define MICROPY_INCLUDED_STM32_USBD_DESC_H #include "usbd_cdc_msc_hid.h" @@ -32,4 +32,4 @@ extern const USBD_DescriptorsTypeDef USBD_Descriptors; void USBD_SetVIDPIDRelease(usbd_cdc_msc_hid_state_t *usbd, uint16_t vid, uint16_t pid, uint16_t device_release_num, int cdc_only); -#endif // MICROPY_INCLUDED_STMHAL_USBD_DESC_H +#endif // MICROPY_INCLUDED_STM32_USBD_DESC_H diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c index 4ee533c21c..3ffc0b425d 100644 --- a/ports/stm32/usbd_hid_interface.c +++ b/ports/stm32/usbd_hid_interface.c @@ -42,8 +42,9 @@ #include "irq.h" #include "usb.h" -uint8_t *usbd_hid_init(usbd_hid_itf_t *hid, usbd_cdc_msc_hid_state_t *usbd) { - hid->usbd = usbd; +uint8_t *usbd_hid_init(usbd_hid_state_t *hid_in) { + usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in; + hid->current_read_buffer = 0; hid->last_read_len = 0; hid->current_write_buffer = 0; @@ -55,13 +56,15 @@ uint8_t *usbd_hid_init(usbd_hid_itf_t *hid, usbd_cdc_msc_hid_state_t *usbd) { // Data received over USB OUT endpoint is processed here. // len: number of bytes received into the buffer we passed to USBD_HID_ReceivePacket // Returns USBD_OK if all operations are OK else USBD_FAIL -int8_t usbd_hid_receive(usbd_hid_itf_t *hid, size_t len) { +int8_t usbd_hid_receive(usbd_hid_state_t *hid_in, size_t len) { + usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in; + hid->current_write_buffer = !hid->current_write_buffer; hid->last_read_len = len; // initiate next USB packet transfer, to append to existing data in buffer - USBD_HID_ReceivePacket(hid->usbd, hid->buffer[hid->current_write_buffer]); + USBD_HID_ReceivePacket(&hid->base, hid->buffer[hid->current_write_buffer]); // Set NAK to indicate we need to process read buffer - USBD_HID_SetNAK(hid->usbd); + USBD_HID_SetNAK(&hid->base); return USBD_OK; } @@ -94,12 +97,13 @@ int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout) } // Copy bytes from device to user buffer - memcpy(buf, hid->buffer[hid->current_read_buffer], hid->last_read_len); + int read_len = hid->last_read_len; + memcpy(buf, hid->buffer[hid->current_read_buffer], read_len); hid->current_read_buffer = !hid->current_read_buffer; // Clear NAK to indicate we are ready to read more data - USBD_HID_ClearNAK(hid->usbd); + USBD_HID_ClearNAK(&hid->base); // Success, return number of bytes read - return hid->last_read_len; + return read_len; } diff --git a/ports/stm32/usbd_hid_interface.h b/ports/stm32/usbd_hid_interface.h index 79040b57e9..777fa93403 100644 --- a/ports/stm32/usbd_hid_interface.h +++ b/ports/stm32/usbd_hid_interface.h @@ -1,13 +1,13 @@ /* * This file is part of the MicroPython project, http://micropython.org/ */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H -#define MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H +#ifndef MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H +#define MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H #include "usbd_cdc_msc_hid.h" typedef struct _usbd_hid_itf_t { - usbd_cdc_msc_hid_state_t *usbd; // the parent USB device + usbd_hid_state_t base; // state for the base HID layer uint8_t buffer[2][HID_DATA_FS_MAX_PACKET_SIZE]; // pair of buffers to read individual packets into int8_t current_read_buffer; // which buffer to read from @@ -18,4 +18,4 @@ typedef struct _usbd_hid_itf_t { int usbd_hid_rx_num(usbd_hid_itf_t *hid); int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout); -#endif // MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H +#endif // MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H diff --git a/ports/stm32/usbd_msc_storage.c b/ports/stm32/usbd_msc_storage.c index f825c3d70d..7d6c19e9fe 100644 --- a/ports/stm32/usbd_msc_storage.c +++ b/ports/stm32/usbd_msc_storage.c @@ -36,7 +36,7 @@ #include "usbd_cdc_msc_hid.h" #include "usbd_msc_storage.h" -#include "py/misc.h" +#include "py/mpstate.h" #include "storage.h" #include "sdcard.h" diff --git a/ports/stm32/usbd_msc_storage.h b/ports/stm32/usbd_msc_storage.h index 6cc40d2d62..669f7df581 100644 --- a/ports/stm32/usbd_msc_storage.h +++ b/ports/stm32/usbd_msc_storage.h @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H -#define MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H +#ifndef MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H +#define MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H extern const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops; extern const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops; -#endif // MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H +#endif // MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H diff --git a/ports/stm32/usbdev/Release_Notes.html b/ports/stm32/usbdev/Release_Notes.html deleted file mode 100644 index 487b455266..0000000000 --- a/ports/stm32/usbdev/Release_Notes.html +++ /dev/null @@ -1,974 +0,0 @@ - - - - - - - - -Release Notes for STM32 USB Device Library - - - - - - - - -
- -

 

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

Back to Release page

-
-

Release Notes for STM32 USB Device Library

-

Copyright - 2014 STMicroelectronics

-

-
-

 

- - - - -
-

Update History

-

V2.0.0 / 18-February-2014

- - - - - -

Main -Changes

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

V1.1.0 / 19-March-2012

-

Main -Changes

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

V1.0.0 / 22-July-2011

Main -Changes

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

-

License

-

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


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

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

-
-

-
- -
- -

 

- -
- - \ No newline at end of file diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index a26b1df0dc..a4f81f10d9 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h @@ -6,12 +6,36 @@ #include "usbd_msc_scsi.h" #include "usbd_ioreq.h" +// These are included to get direct access the MICROPY_HW_USB_xxx config +#include "mpconfigboard.h" +#include "mpconfigboard_common.h" + +// Work out if we should support USB high-speed device mode +#if MICROPY_HW_USB_HS \ + && (!MICROPY_HW_USB_HS_IN_FS || defined(STM32F723xx) || defined(STM32F733xx)) +#define USBD_SUPPORT_HS_MODE (1) +#else +#define USBD_SUPPORT_HS_MODE (0) +#endif + // Needed for the CDC+MSC+HID state and should be maximum of all template // config descriptors defined in usbd_cdc_msc_hid.c +#if MICROPY_HW_USB_ENABLE_CDC2 +#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#else #define MAX_TEMPLATE_CONFIG_DESC_SIZE (107) +#endif // CDC, MSC and HID packet sizes +#define MSC_FS_MAX_PACKET (64) +#define MSC_HS_MAX_PACKET (512) #define CDC_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size +#define CDC_DATA_HS_MAX_PACKET_SIZE (512) // endpoint IN & OUT packet size +#if USBD_SUPPORT_HS_MODE +#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE +#else +#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE +#endif #define MSC_MEDIA_PACKET (2048) // was 8192; how low can it go whilst still working? #define HID_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size @@ -19,26 +43,18 @@ #define MSC_IN_EP (0x81) #define MSC_OUT_EP (0x01) -// Need to define here for usbd_cdc_interface.c (it needs CDC_IN_EP) -#define CDC_IN_EP (0x83) -#define CDC_OUT_EP (0x03) -#define CDC_CMD_EP (0x82) +struct _usbd_cdc_msc_hid_state_t; typedef struct { - uint32_t bitrate; - uint8_t format; - uint8_t paritytype; - uint8_t datatype; -} USBD_CDC_LineCodingTypeDef; - -typedef struct { - uint32_t data[CDC_DATA_FS_MAX_PACKET_SIZE/4]; /* Force 32bits alignment */ - uint8_t CmdOpCode; - uint8_t CmdLength; - - __IO uint32_t TxState; - __IO uint32_t RxState; -} USBD_CDC_HandleTypeDef; + struct _usbd_cdc_msc_hid_state_t *usbd; // The parent USB device + uint32_t ctl_packet_buf[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32-bit alignment + uint8_t iface_num; + uint8_t in_ep; + uint8_t out_ep; + uint8_t cur_request; + uint8_t cur_length; + volatile uint8_t tx_in_progress; +} usbd_cdc_state_t; typedef struct _USBD_STORAGE { int8_t (* Init) (uint8_t lun); @@ -83,35 +99,36 @@ typedef enum { } HID_StateTypeDef; typedef struct { - uint32_t Protocol; - uint32_t IdleState; - uint32_t AltSetting; - HID_StateTypeDef state; -} USBD_HID_HandleTypeDef; + struct _usbd_cdc_msc_hid_state_t *usbd; // The parent USB device + uint8_t iface_num; + uint8_t in_ep; + uint8_t out_ep; + uint8_t state; + uint8_t ctl_protocol; + uint8_t ctl_idle_state; + uint8_t ctl_alt_setting; + uint8_t *desc; + const uint8_t *report_desc; +} usbd_hid_state_t; typedef struct _usbd_cdc_msc_hid_state_t { USBD_HandleTypeDef *pdev; uint8_t usbd_mode; - uint8_t cdc_iface_num; - uint8_t hid_in_ep; - uint8_t hid_out_ep; - uint8_t hid_iface_num; uint8_t usbd_config_desc_size; - uint8_t *hid_desc; - const uint8_t *hid_report_desc; - USBD_CDC_HandleTypeDef CDC_ClassData; USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData; - USBD_HID_HandleTypeDef HID_ClassData; // RAM to hold the current descriptors, which we configure on the fly __ALIGN_BEGIN uint8_t usbd_device_desc[USB_LEN_DEV_DESC] __ALIGN_END; __ALIGN_BEGIN uint8_t usbd_str_desc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END; __ALIGN_BEGIN uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END; - void *cdc; - void *hid; + usbd_cdc_state_t *cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + usbd_cdc_state_t *cdc2; + #endif + usbd_hid_state_t *hid; } usbd_cdc_msc_hid_state_t; #define USBD_HID_MOUSE_MAX_PACKET (4) @@ -126,33 +143,53 @@ extern const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_ extern const USBD_ClassTypeDef USBD_CDC_MSC_HID; +static inline uint32_t usbd_msc_max_packet(USBD_HandleTypeDef *pdev) { + #if USBD_SUPPORT_HS_MODE + if (pdev->dev_speed == USBD_SPEED_HIGH) { + return MSC_HS_MAX_PACKET; + } else + #endif + { + return MSC_FS_MAX_PACKET; + } +} + +static inline uint32_t usbd_cdc_max_packet(USBD_HandleTypeDef *pdev) { + #if USBD_SUPPORT_HS_MODE + if (pdev->dev_speed == USBD_SPEED_HIGH) { + return CDC_DATA_HS_MAX_PACKET_SIZE; + } else + #endif + { + return CDC_DATA_FS_MAX_PACKET_SIZE; + } +} + // returns 0 on success, -1 on failure int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info); // returns the current usb mode uint8_t USBD_GetMode(usbd_cdc_msc_hid_state_t *usbd); -uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf); -uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, const uint8_t *buf); +uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf); +uint8_t USBD_CDC_TransmitPacket(usbd_cdc_state_t *cdc, size_t len, const uint8_t *buf); static inline void USBD_MSC_RegisterStorage(usbd_cdc_msc_hid_state_t *usbd, USBD_StorageTypeDef *fops) { usbd->MSC_BOT_ClassData.bdev_ops = fops; } -uint8_t USBD_HID_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf); -int USBD_HID_CanSendReport(usbd_cdc_msc_hid_state_t *usbd); -uint8_t USBD_HID_SendReport(usbd_cdc_msc_hid_state_t *usbd, uint8_t *report, uint16_t len); -uint8_t USBD_HID_SetNAK(usbd_cdc_msc_hid_state_t *usbd); -uint8_t USBD_HID_ClearNAK(usbd_cdc_msc_hid_state_t *usbd); +uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *usbd, uint8_t *buf); +int USBD_HID_CanSendReport(usbd_hid_state_t *usbd); +uint8_t USBD_HID_SendReport(usbd_hid_state_t *usbd, uint8_t *report, uint16_t len); +uint8_t USBD_HID_SetNAK(usbd_hid_state_t *usbd); +uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *usbd); // These are provided externally to implement the CDC interface -struct _usbd_cdc_itf_t; -uint8_t *usbd_cdc_init(struct _usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd); -int8_t usbd_cdc_control(struct _usbd_cdc_itf_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length); -int8_t usbd_cdc_receive(struct _usbd_cdc_itf_t *cdc, size_t len); +uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc); +int8_t usbd_cdc_control(usbd_cdc_state_t *cdc, uint8_t cmd, uint8_t* pbuf, uint16_t length); +int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc, size_t len); // These are provided externally to implement the HID interface -struct _usbd_hid_itf_t; -uint8_t *usbd_hid_init(struct _usbd_hid_itf_t *hid, usbd_cdc_msc_hid_state_t *usbd); -int8_t usbd_hid_receive(struct _usbd_hid_itf_t *hid, size_t len); +uint8_t *usbd_hid_init(usbd_hid_state_t *hid); +int8_t usbd_hid_receive(usbd_hid_state_t *hid, size_t len); #endif // _USB_CDC_MSC_CORE_H_ diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h index 08882bb1ae..c876dcf298 100644 --- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h +++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H -#define MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H +#ifndef MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H +#define MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H // these are exports for the CDC/MSC/HID interface that are independent // from any other definitions/declarations @@ -34,9 +34,12 @@ typedef enum { USBD_MODE_CDC = 0x01, USBD_MODE_MSC = 0x02, USBD_MODE_HID = 0x04, - USBD_MODE_CDC_MSC = 0x03, - USBD_MODE_CDC_HID = 0x05, - USBD_MODE_MSC_HID = 0x06, + USBD_MODE_CDC2 = 0x08, + USBD_MODE_CDC_MSC = USBD_MODE_CDC | USBD_MODE_MSC, + USBD_MODE_CDC_HID = USBD_MODE_CDC | USBD_MODE_HID, + USBD_MODE_MSC_HID = USBD_MODE_MSC | USBD_MODE_HID, + USBD_MODE_CDC2_MSC = USBD_MODE_CDC | USBD_MODE_MSC | USBD_MODE_CDC2, + USBD_MODE_HIGH_SPEED = 0x80, // or with one of the above } usb_device_mode_t; typedef struct _USBD_HID_ModeInfoTypeDef { @@ -48,4 +51,4 @@ typedef struct _USBD_HID_ModeInfoTypeDef { const uint8_t *report_desc; } USBD_HID_ModeInfoTypeDef; -#endif // MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H +#endif // MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H diff --git a/ports/stm32/usbdev/class/inc/usbd_msc_bot.h b/ports/stm32/usbdev/class/inc/usbd_msc_bot.h index 41f8ab5a53..4edc912fe1 100644 --- a/ports/stm32/usbdev/class/inc/usbd_msc_bot.h +++ b/ports/stm32/usbdev/class/inc/usbd_msc_bot.h @@ -1,151 +1,151 @@ -/** - ****************************************************************************** - * @file usbd_msc_bot.h - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief header for the usbd_msc_bot.c file - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USBD_MSC_SCSI_H +#define __USBD_MSC_SCSI_H + +/* Includes ------------------------------------------------------------------*/ +#include "usbd_def.h" + +/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY + * @{ + */ + +/** @defgroup USBD_SCSI + * @brief header file for the storage disk file + * @{ + */ + +/** @defgroup USBD_SCSI_Exported_Defines + * @{ + */ + +#define SENSE_LIST_DEEPTH 4 + +/* SCSI Commands */ +#define SCSI_FORMAT_UNIT 0x04 +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SELECT6 0x15 +#define SCSI_MODE_SELECT10 0x55 +#define SCSI_MODE_SENSE6 0x1A +#define SCSI_MODE_SENSE10 0x5A +#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_SYNCHRONIZE_CACHE10 0x35 +#define SCSI_SYNCHRONIZE_CACHE16 0x91 +#define SCSI_READ6 0x08 +#define SCSI_READ10 0x28 +#define SCSI_READ12 0xA8 +#define SCSI_READ16 0x88 + +#define SCSI_READ_CAPACITY10 0x25 +#define SCSI_READ_CAPACITY16 0x9E + +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_START_STOP_UNIT 0x1B +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_WRITE6 0x0A +#define SCSI_WRITE10 0x2A +#define SCSI_WRITE12 0xAA +#define SCSI_WRITE16 0x8A + +#define SCSI_VERIFY10 0x2F +#define SCSI_VERIFY12 0xAF +#define SCSI_VERIFY16 0x8F + +#define SCSI_SEND_DIAGNOSTIC 0x1D +#define SCSI_READ_FORMAT_CAPACITIES 0x23 + +#define NO_SENSE 0 +#define RECOVERED_ERROR 1 +#define NOT_READY 2 +#define MEDIUM_ERROR 3 +#define HARDWARE_ERROR 4 +#define ILLEGAL_REQUEST 5 +#define UNIT_ATTENTION 6 +#define DATA_PROTECT 7 +#define BLANK_CHECK 8 +#define VENDOR_SPECIFIC 9 +#define COPY_ABORTED 10 +#define ABORTED_COMMAND 11 +#define VOLUME_OVERFLOW 13 +#define MISCOMPARE 14 + + +#define INVALID_CDB 0x20 +#define INVALID_FIELED_IN_COMMAND 0x24 +#define PARAMETER_LIST_LENGTH_ERROR 0x1A +#define INVALID_FIELD_IN_PARAMETER_LIST 0x26 +#define ADDRESS_OUT_OF_RANGE 0x21 +#define MEDIUM_NOT_PRESENT 0x3A +#define MEDIUM_HAVE_CHANGED 0x28 +#define WRITE_PROTECTED 0x27 +#define UNRECOVERED_READ_ERROR 0x11 +#define WRITE_FAULT 0x03 + +#define READ_FORMAT_CAPACITY_DATA_LEN 0x0C +#define READ_CAPACITY10_DATA_LEN 0x08 +#define MODE_SENSE10_DATA_LEN 0x08 +#define MODE_SENSE6_DATA_LEN 0x04 +#define REQUEST_SENSE_DATA_LEN 0x12 +#define STANDARD_INQUIRY_DATA_LEN 0x24 +#define BLKVFY 0x04 + +extern uint8_t Page00_Inquiry_Data[]; +extern uint8_t Standard_Inquiry_Data[]; +extern uint8_t Standard_Inquiry_Data2[]; +extern uint8_t Mode_Sense6_data[]; +extern uint8_t Mode_Sense10_data[]; +extern uint8_t Scsi_Sense_Data[]; +extern uint8_t ReadCapacity10_Data[]; +extern uint8_t ReadFormatCapacity_Data []; +/** + * @} + */ + + +/** @defgroup USBD_SCSI_Exported_TypesDefinitions + * @{ + */ + +typedef struct _SENSE_ITEM { + char Skey; + union { + struct _ASCs { + char ASC; + char ASCQ; + }b; + unsigned int ASC; + char *pData; + } w; +} USBD_SCSI_SenseTypeDef; +/** + * @} + */ + +/** @defgroup USBD_SCSI_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup USBD_SCSI_Exported_Variables + * @{ + */ + +/** + * @} + */ +/** @defgroup USBD_SCSI_Exported_FunctionsPrototype + * @{ + */ +int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, + uint8_t lun, + uint8_t *cmd); + +void SCSI_SenseCode(USBD_HandleTypeDef *pdev, + uint8_t lun, + uint8_t sKey, + uint8_t ASC); + +/** + * @} + */ + +#endif /* __USBD_MSC_SCSI_H */ +/** + * @} + */ + +/** + * @} + */ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 379a8f32ce..c5aac037d3 100644 --- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c +++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c @@ -24,13 +24,31 @@ * THE SOFTWARE. */ +#include STM32_HAL_H #include "usbd_ioreq.h" #include "usbd_cdc_msc_hid.h" +#if MICROPY_HW_ENABLE_USB + +#define MSC_TEMPLATE_CONFIG_DESC_SIZE (32) +#define MSC_TEMPLATE_MSC_DESC_OFFSET (9) #define CDC_TEMPLATE_CONFIG_DESC_SIZE (67) #define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98) +#define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40) +#define CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58)) +#define CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET (9 + 23 + 8) +#define CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET (9 + 23 + (8 + 58) + 8) #define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107) #define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9) +#define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49) +#define CDC_TEMPLATE_CDC_DESC_OFFSET (9) +#define CDC_DESC_OFFSET_INTR_INTERVAL (34) +#define CDC_DESC_OFFSET_OUT_MAX_PACKET_LO (48) +#define CDC_DESC_OFFSET_OUT_MAX_PACKET_HI (49) +#define CDC_DESC_OFFSET_IN_MAX_PACKET_LO (55) +#define CDC_DESC_OFFSET_IN_MAX_PACKET_HI (56) #define HID_DESC_OFFSET_SUBCLASS (6) #define HID_DESC_OFFSET_PROTOCOL (7) #define HID_DESC_OFFSET_SUBDESC (9) @@ -45,10 +63,20 @@ #define CDC_IFACE_NUM_ALONE (0) #define CDC_IFACE_NUM_WITH_MSC (1) +#define CDC2_IFACE_NUM_WITH_MSC (3) #define CDC_IFACE_NUM_WITH_HID (1) #define MSC_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_MSC (1) + +#define CDC_IN_EP (0x83) +#define CDC_OUT_EP (0x03) +#define CDC_CMD_EP (0x82) + +#define CDC2_IN_EP (0x85) +#define CDC2_OUT_EP (0x05) +#define CDC2_CMD_EP (0x84) + #define HID_IN_EP_WITH_CDC (0x81) #define HID_OUT_EP_WITH_CDC (0x01) #define HID_IN_EP_WITH_MSC (0x83) @@ -57,10 +85,7 @@ #define USB_DESC_TYPE_ASSOCIATION (0x0b) #define CDC_CMD_PACKET_SIZE (8) // Control Endpoint Packet size -#define CDC_DATA_IN_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE -#define CDC_DATA_OUT_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE -#define MSC_MAX_PACKET (0x40) #define BOT_GET_MAX_LUN (0xfe) #define BOT_RESET (0xff) @@ -71,8 +96,7 @@ #define HID_REQ_SET_IDLE (0x0a) #define HID_REQ_GET_IDLE (0x02) -/* -// this is used only in high-speed mode, which we don't support +#if USBD_SUPPORT_HS_MODE // USB Standard Device Descriptor __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = { USB_LEN_DEV_QUALIFIER_DESC, @@ -82,11 +106,59 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QU 0x00, 0x00, 0x00, - 0x40, // same for CDC and MSC (latter being MSC_MAX_PACKET), HID is 0x04 + 0x40, // same for CDC and MSC (latter being MSC_FS_MAX_PACKET), HID is 0x04 0x01, 0x00, }; -*/ +#endif + +// USB MSC device Configuration Descriptor +static const uint8_t msc_template_config_desc[MSC_TEMPLATE_CONFIG_DESC_SIZE] = { + //-------------------------------------------------------------------------- + // Configuration Descriptor + 0x09, // bLength: Configuration Descriptor size + USB_DESC_TYPE_CONFIGURATION, // bDescriptorType: Configuration + LOBYTE(MSC_TEMPLATE_CONFIG_DESC_SIZE), // wTotalLength: no of returned bytes + HIBYTE(MSC_TEMPLATE_CONFIG_DESC_SIZE), + 0x01, // bNumInterfaces: 1 interfaces + 0x01, // bConfigurationValue: Configuration value + 0x00, // iConfiguration: Index of string descriptor describing the configuration + 0x80, // bmAttributes: bus powered; 0xc0 for self powered + 0xfa, // bMaxPower: in units of 2mA + + //========================================================================== + // MSC only has 1 interface so doesn't need an IAD + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_DESC_TYPE_INTERFACE, // bDescriptorType: interface descriptor + MSC_IFACE_NUM_WITH_CDC, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints + 0x08, // bInterfaceClass: MSC Class + 0x06, // bInterfaceSubClass : SCSI transparent + 0x50, // nInterfaceProtocol + 0x00, // iInterface: + + // Endpoint IN descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + MSC_IN_EP, // bEndpointAddress: IN, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer + + // Endpoint OUT descriptor + 0x07, // bLength: Endpoint descriptor length + USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type + MSC_OUT_EP, // bEndpointAddress: OUT, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer +}; // USB CDC MSC device Configuration Descriptor static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE] = { @@ -122,8 +194,8 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type MSC_IN_EP, // bEndpointAddress: IN, address 3 0x02, // bmAttributes: Bulk endpoint type - LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_MAX_PACKET), + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), 0x00, // bInterval: ignore for Bulk transfer // Endpoint OUT descriptor @@ -131,8 +203,8 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type MSC_OUT_EP, // bEndpointAddress: OUT, address 3 0x02, // bmAttributes: Bulk endpoint type - LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_MAX_PACKET), + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), 0x00, // bInterval: ignore for Bulk transfer //========================================================================== @@ -553,26 +625,56 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode // construct config desc switch (usbd->usbd_mode) { + case USBD_MODE_MSC: + usbd->usbd_config_desc_size = sizeof(msc_template_config_desc); + memcpy(usbd->usbd_config_desc, msc_template_config_desc, sizeof(msc_template_config_desc)); + break; + case USBD_MODE_CDC_MSC: usbd->usbd_config_desc_size = sizeof(cdc_msc_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); - usbd->cdc_iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; break; + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: { + usbd->usbd_config_desc_size = CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE; + uint8_t *d = usbd->usbd_config_desc; + memcpy(d, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); + d[2] = LOBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); // wTotalLength + d[3] = HIBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); + d[4] = 5; // bNumInterfaces + memcpy(d + 9 + 23 + (8 + 58), d + 9 + 23, 8 + 58); + d += 9 + 23 + (8 + 58); + d[2] = CDC2_IFACE_NUM_WITH_MSC; // bFirstInterface + d[10] = CDC2_IFACE_NUM_WITH_MSC; // bInterfaceNumber + d[26] = CDC2_IFACE_NUM_WITH_MSC + 1; // bDataInterface + d[34] = CDC2_IFACE_NUM_WITH_MSC + 0; // bMasterInterface + d[35] = CDC2_IFACE_NUM_WITH_MSC + 1; // bSlaveInterface + d[38] = CDC2_CMD_EP; // bEndpointAddress + d[45] = CDC2_IFACE_NUM_WITH_MSC + 1; // bInterfaceNumber + d[54] = CDC2_OUT_EP; // bEndpointAddress + d[61] = CDC2_IN_EP; // bEndpointAddress + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC; + usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_MSC; + break; + } + #endif + case USBD_MODE_CDC_HID: usbd->usbd_config_desc_size = sizeof(cdc_hid_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc)); - usbd->cdc_iface_num = CDC_IFACE_NUM_WITH_HID; - usbd->hid_in_ep = HID_IN_EP_WITH_CDC; - usbd->hid_out_ep = HID_OUT_EP_WITH_CDC; - usbd->hid_iface_num = HID_IFACE_NUM_WITH_CDC; - usbd->hid_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_HID_DESC_OFFSET; + usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_HID; + usbd->hid->in_ep = HID_IN_EP_WITH_CDC; + usbd->hid->out_ep = HID_OUT_EP_WITH_CDC; + usbd->hid->iface_num = HID_IFACE_NUM_WITH_CDC; + usbd->hid->desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_HID_DESC_OFFSET; break; case USBD_MODE_CDC: usbd->usbd_config_desc_size = sizeof(cdc_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_template_config_desc, sizeof(cdc_template_config_desc)); - usbd->cdc_iface_num = CDC_IFACE_NUM_ALONE; + usbd->cdc->iface_num = CDC_IFACE_NUM_ALONE; break; /* @@ -589,9 +691,21 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode return -1; } + if (usbd->usbd_mode & USBD_MODE_CDC) { + usbd->cdc->in_ep = CDC_IN_EP; + usbd->cdc->out_ep = CDC_OUT_EP; + } + + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + usbd->cdc2->in_ep = CDC2_IN_EP; + usbd->cdc2->out_ep = CDC2_OUT_EP; + } + #endif + // configure the HID descriptor, if needed if (usbd->usbd_mode & USBD_MODE_HID) { - uint8_t *hid_desc = usbd->hid_desc; + uint8_t *hid_desc = usbd->hid->desc; hid_desc[HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass; hid_desc[HID_DESC_OFFSET_PROTOCOL] = hid_info->protocol; hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN] = hid_info->report_desc_len; @@ -601,66 +715,70 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] = hid_info->max_packet_len; hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] = 0; hid_desc[HID_DESC_OFFSET_POLLING_INTERVAL_OUT] = hid_info->polling_interval; - usbd->hid_report_desc = hid_info->report_desc; + usbd->hid->report_desc = hid_info->report_desc; } return 0; } +static void usbd_cdc_state_init(USBD_HandleTypeDef *pdev, usbd_cdc_msc_hid_state_t *usbd, usbd_cdc_state_t *cdc, uint8_t cmd_ep) { + int mp = usbd_cdc_max_packet(pdev); + + // Open endpoints + USBD_LL_OpenEP(pdev, cdc->in_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cdc->out_ep, USBD_EP_TYPE_BULK, mp); + USBD_LL_OpenEP(pdev, cmd_ep, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE); + + // Init state + cdc->usbd = usbd; + cdc->cur_request = 0xff; + cdc->tx_in_progress = 0; + + // Init interface + uint8_t *buf = usbd_cdc_init(cdc); + + // Prepare Out endpoint to receive next packet + USBD_LL_PrepareReceive(pdev, cdc->out_ep, buf, mp); +} + static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + #if !USBD_SUPPORT_HS_MODE if (pdev->dev_speed == USBD_SPEED_HIGH) { // can't handle high speed return 1; } + #endif usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; if (usbd->usbd_mode & USBD_MODE_CDC) { // CDC VCP component - - // Open EP IN - USBD_LL_OpenEP(pdev, - CDC_IN_EP, - USBD_EP_TYPE_BULK, - CDC_DATA_IN_PACKET_SIZE); - - // Open EP OUT - USBD_LL_OpenEP(pdev, - CDC_OUT_EP, - USBD_EP_TYPE_BULK, - CDC_DATA_OUT_PACKET_SIZE); - - // Open Command IN EP - USBD_LL_OpenEP(pdev, - CDC_CMD_EP, - USBD_EP_TYPE_INTR, - CDC_CMD_PACKET_SIZE); - - // Init physical Interface components - uint8_t *buf = usbd_cdc_init(usbd->cdc, usbd); - - // Init Xfer states - usbd->CDC_ClassData.TxState = 0; - usbd->CDC_ClassData.RxState = 0; - - // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, CDC_DATA_OUT_PACKET_SIZE); + usbd_cdc_state_init(pdev, usbd, usbd->cdc, CDC_CMD_EP); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->usbd_mode & USBD_MODE_CDC2) { + // CDC VCP #2 component + usbd_cdc_state_init(pdev, usbd, usbd->cdc2, CDC2_CMD_EP); + } + #endif + if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component + int mp = usbd_msc_max_packet(pdev); + // Open EP OUT USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, - MSC_MAX_PACKET); + mp); // Open EP IN USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, - MSC_MAX_PACKET); + mp); // Init the BOT layer MSC_BOT_Init(pdev); @@ -671,30 +789,26 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { // get max packet lengths from descriptor uint16_t mps_in = - usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_LO] - | (usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_HI] << 8); + usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_LO] + | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_HI] << 8); uint16_t mps_out = - usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] - | (usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); + usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] + | (usbd->hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); // Open EP IN - USBD_LL_OpenEP(pdev, - usbd->hid_in_ep, - USBD_EP_TYPE_INTR, - mps_in); + USBD_LL_OpenEP(pdev, usbd->hid->in_ep, USBD_EP_TYPE_INTR, mps_in); // Open EP OUT - USBD_LL_OpenEP(pdev, - usbd->hid_out_ep, - USBD_EP_TYPE_INTR, - mps_out); + USBD_LL_OpenEP(pdev, usbd->hid->out_ep, USBD_EP_TYPE_INTR, mps_out); - uint8_t *buf = usbd_hid_init(usbd->hid, usbd); + + usbd->hid->usbd = usbd; + uint8_t *buf = usbd_hid_init(usbd->hid); // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(pdev, usbd->hid_out_ep, buf, mps_out); + USBD_LL_PrepareReceive(pdev, usbd->hid->out_ep, buf, mps_out); - usbd->HID_ClassData.state = HID_IDLE; + usbd->hid->state = HID_IDLE; } return 0; @@ -712,6 +826,17 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) USBD_LL_CloseEP(pdev, CDC_CMD_EP); } + #if MICROPY_HW_USB_ENABLE_CDC2 + if ((usbd->usbd_mode & USBD_MODE_CDC2) && usbd->cdc2) { + // CDC VCP #2 component + + // close endpoints + USBD_LL_CloseEP(pdev, CDC2_IN_EP); + USBD_LL_CloseEP(pdev, CDC2_OUT_EP); + USBD_LL_CloseEP(pdev, CDC2_CMD_EP); + } + #endif + if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component @@ -727,8 +852,8 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) // HID component // close endpoints - USBD_LL_CloseEP(pdev, usbd->hid_in_ep); - USBD_LL_CloseEP(pdev, usbd->hid_out_ep); + USBD_LL_CloseEP(pdev, usbd->hid->in_ep); + USBD_LL_CloseEP(pdev, usbd->hid->out_ep); } return 0; @@ -754,31 +879,75 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + // Work out the recipient of the setup request + uint8_t mode = usbd->usbd_mode; + uint8_t recipient = 0; + usbd_cdc_state_t *cdc = NULL; + switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) { + case USB_REQ_RECIPIENT_INTERFACE: { + uint16_t iface = req->wIndex; + if ((mode & USBD_MODE_CDC) && iface == usbd->cdc->iface_num) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && iface == usbd->cdc2->iface_num) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif + } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { + recipient = USBD_MODE_MSC; + } else if ((mode & USBD_MODE_HID) && iface == usbd->hid->iface_num) { + recipient = USBD_MODE_HID; + } + break; + } + case USB_REQ_RECIPIENT_ENDPOINT: { + uint8_t ep = req->wIndex & 0x7f; + if ((mode & USBD_MODE_CDC) && (ep == CDC_OUT_EP || ep == (CDC_CMD_EP & 0x7f))) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((mode & USBD_MODE_CDC2) && (ep == CDC2_OUT_EP || ep == (CDC2_CMD_EP & 0x7f))) { + recipient = USBD_MODE_CDC; + cdc = usbd->cdc2; + #endif + } else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) { + recipient = USBD_MODE_MSC; + } else if ((mode & USBD_MODE_HID) && ep == usbd->hid->out_ep) { + recipient = USBD_MODE_HID; + } + break; + } + } + + // Fail the request if we didn't have a valid recipient + if (recipient == 0) { + USBD_CtlError(pdev, req); + return USBD_FAIL; + } + switch (req->bmRequest & USB_REQ_TYPE_MASK) { // Class request case USB_REQ_TYPE_CLASS: - // req->wIndex is the recipient interface number - if ((usbd->usbd_mode & USBD_MODE_CDC) && req->wIndex == usbd->cdc_iface_num) { - // CDC component + if (recipient == USBD_MODE_CDC) { if (req->wLength) { if (req->bmRequest & 0x80) { // device-to-host request - usbd_cdc_control(usbd->cdc, req->bRequest, (uint8_t*)usbd->CDC_ClassData.data, req->wLength); - USBD_CtlSendData(pdev, (uint8_t*)usbd->CDC_ClassData.data, req->wLength); + usbd_cdc_control(cdc, req->bRequest, (uint8_t*)cdc->ctl_packet_buf, req->wLength); + USBD_CtlSendData(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); } else { // host-to-device request - usbd->CDC_ClassData.CmdOpCode = req->bRequest; - usbd->CDC_ClassData.CmdLength = req->wLength; - USBD_CtlPrepareRx(pdev, (uint8_t*)usbd->CDC_ClassData.data, req->wLength); + cdc->cur_request = req->bRequest; + cdc->cur_length = req->wLength; + USBD_CtlPrepareRx(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength); } } else { // Not a Data request // Transfer the command to the interface layer - return usbd_cdc_control(usbd->cdc, req->bRequest, NULL, req->wValue); + return usbd_cdc_control(cdc, req->bRequest, NULL, req->wValue); } - } else if ((usbd->usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) { - // MSC component + } else if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { case BOT_GET_MAX_LUN: if ((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) { @@ -803,22 +972,22 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp USBD_CtlError(pdev, req); return USBD_FAIL; } - } else if ((usbd->usbd_mode & USBD_MODE_HID) && req->wIndex == usbd->hid_iface_num) { + } else if (recipient == USBD_MODE_HID) { switch (req->bRequest) { case HID_REQ_SET_PROTOCOL: - usbd->HID_ClassData.Protocol = (uint8_t)(req->wValue); + usbd->hid->ctl_protocol = (uint8_t)(req->wValue); break; case HID_REQ_GET_PROTOCOL: - USBD_CtlSendData(pdev, (uint8_t *)&usbd->HID_ClassData.Protocol, 1); + USBD_CtlSendData(pdev, &usbd->hid->ctl_protocol, 1); break; case HID_REQ_SET_IDLE: - usbd->HID_ClassData.IdleState = (uint8_t)(req->wValue >> 8); + usbd->hid->ctl_idle_state = (uint8_t)(req->wValue >> 8); break; case HID_REQ_GET_IDLE: - USBD_CtlSendData(pdev, (uint8_t *)&usbd->HID_ClassData.IdleState, 1); + USBD_CtlSendData(pdev, &usbd->hid->ctl_idle_state, 1); break; default: @@ -828,9 +997,8 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp } break; - // Interface & Endpoint request case USB_REQ_TYPE_STANDARD: - if ((usbd->usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) { + if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { case USB_REQ_GET_INTERFACE : USBD_CtlSendData(pdev, (uint8_t *)&usbd->MSC_BOT_ClassData.interface, 1); @@ -848,38 +1016,38 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp USBD_LL_CloseEP(pdev, (uint8_t)req->wIndex); if((((uint8_t)req->wIndex) & 0x80) == 0x80) { // Open EP IN - USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, MSC_MAX_PACKET); + USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, usbd_msc_max_packet(pdev)); } else { // Open EP OUT - USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, MSC_MAX_PACKET); + USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, usbd_msc_max_packet(pdev)); } // Handle BOT error MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex); break; } - } else if ((usbd->usbd_mode & USBD_MODE_HID) && req->wIndex == usbd->hid_iface_num) { + } else if (recipient == USBD_MODE_HID) { switch (req->bRequest) { case USB_REQ_GET_DESCRIPTOR: { uint16_t len = 0; const uint8_t *pbuf = NULL; if (req->wValue >> 8 == HID_REPORT_DESC) { - len = usbd->hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN]; + len = usbd->hid->desc[HID_DESC_OFFSET_REPORT_DESC_LEN]; len = MIN(len, req->wLength); - pbuf = usbd->hid_report_desc; + pbuf = usbd->hid->report_desc; } else if (req->wValue >> 8 == HID_DESCRIPTOR_TYPE) { len = MIN(HID_SUBDESC_LEN, req->wLength); - pbuf = usbd->hid_desc + HID_DESC_OFFSET_SUBDESC; + pbuf = usbd->hid->desc + HID_DESC_OFFSET_SUBDESC; } USBD_CtlSendData(pdev, (uint8_t*)pbuf, len); break; } case USB_REQ_GET_INTERFACE: - USBD_CtlSendData(pdev, (uint8_t *)&usbd->HID_ClassData.AltSetting, 1); + USBD_CtlSendData(pdev, &usbd->hid->ctl_alt_setting, 1); break; case USB_REQ_SET_INTERFACE: - usbd->HID_ClassData.AltSetting = (uint8_t)(req->wValue); + usbd->hid->ctl_alt_setting = (uint8_t)(req->wValue); break; } } @@ -895,10 +1063,16 @@ static uint8_t EP0_TxSent(USBD_HandleTypeDef *pdev) { static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; - if (usbd->cdc != NULL && usbd->CDC_ClassData.CmdOpCode != 0xff) { - usbd_cdc_control(usbd->cdc, usbd->CDC_ClassData.CmdOpCode, (uint8_t*)usbd->CDC_ClassData.data, usbd->CDC_ClassData.CmdLength); - usbd->CDC_ClassData.CmdOpCode = 0xff; + if (usbd->cdc != NULL && usbd->cdc->cur_request != 0xff) { + usbd_cdc_control(usbd->cdc, usbd->cdc->cur_request, (uint8_t*)usbd->cdc->ctl_packet_buf, usbd->cdc->cur_length); + usbd->cdc->cur_request = 0xff; } + #if MICROPY_HW_USB_ENABLE_CDC2 + if (usbd->cdc2 != NULL && usbd->cdc2->cur_request != 0xff) { + usbd_cdc_control(usbd->cdc2, usbd->cdc2->cur_request, (uint8_t*)usbd->cdc2->ctl_packet_buf, usbd->cdc2->cur_length); + usbd->cdc2->cur_request = 0xff; + } + #endif return USBD_OK; } @@ -906,15 +1080,20 @@ static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) { static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; if ((usbd->usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) { - usbd->CDC_ClassData.TxState = 0; + usbd->cdc->tx_in_progress = 0; return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && (epnum == (CDC2_IN_EP & 0x7f) || epnum == (CDC2_CMD_EP & 0x7f))) { + usbd->cdc2->tx_in_progress = 0; + return USBD_OK; + #endif } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) { MSC_BOT_DataIn(pdev, epnum); return USBD_OK; - } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid_in_ep & 0x7f)) { + } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid->in_ep & 0x7f)) { /* Ensure that the FIFO is empty before a new transfer, this condition could be caused by a new transfer before the end of the previous transfer */ - usbd->HID_ClassData.state = HID_IDLE; + usbd->hid->state = HID_IDLE; return USBD_OK; } @@ -932,10 +1111,16 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) usbd_cdc_receive(usbd->cdc, len); return USBD_OK; + #if MICROPY_HW_USB_ENABLE_CDC2 + } else if ((usbd->usbd_mode & USBD_MODE_CDC2) && epnum == (CDC2_OUT_EP & 0x7f)) { + size_t len = USBD_LL_GetRxDataSize(pdev, epnum); + usbd_cdc_receive(usbd->cdc2, len); + return USBD_OK; + #endif } else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) { MSC_BOT_DataOut(pdev, epnum); return USBD_OK; - } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid_out_ep & 0x7f)) { + } else if ((usbd->usbd_mode & USBD_MODE_HID) && epnum == (usbd->hid->out_ep & 0x7f)) { size_t len = USBD_LL_GetRxDataSize(pdev, epnum); usbd_hid_receive(usbd->hid, len); } @@ -943,30 +1128,101 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) return USBD_OK; } +#if USBD_SUPPORT_HS_MODE +static void usbd_cdc_desc_config_max_packet(USBD_HandleTypeDef *pdev, uint8_t *cdc_desc) { + uint32_t mp = usbd_cdc_max_packet(pdev); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); + uint8_t interval; // polling interval in frames of 1ms + if (pdev->dev_speed == USBD_SPEED_HIGH) { + interval = 0x09; + } else { + interval = 0x20; + } + cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; +} +#endif + static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + + #if USBD_SUPPORT_HS_MODE + uint8_t *cdc_desc = NULL; + #if MICROPY_HW_USB_ENABLE_CDC2 + uint8_t *cdc2_desc = NULL; + #endif + uint8_t *msc_desc = NULL; + switch (usbd->usbd_mode) { + case USBD_MODE_MSC: + msc_desc = usbd->usbd_config_desc + MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + + case USBD_MODE_CDC_MSC: + cdc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_CDC_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + + #if MICROPY_HW_USB_ENABLE_CDC2 + case USBD_MODE_CDC2_MSC: + cdc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET; + cdc2_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + #endif + + case USBD_MODE_CDC_HID: + cdc_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET; + break; + + case USBD_MODE_CDC: + cdc_desc = usbd->usbd_config_desc + CDC_TEMPLATE_CDC_DESC_OFFSET; + break; + } + + // configure CDC descriptors, if needed + if (cdc_desc != NULL) { + usbd_cdc_desc_config_max_packet(pdev, cdc_desc); + } + + #if MICROPY_HW_USB_ENABLE_CDC2 + if (cdc2_desc != NULL) { + usbd_cdc_desc_config_max_packet(pdev, cdc2_desc); + } + #endif + + if (msc_desc != NULL) { + uint32_t mp = usbd_msc_max_packet(pdev); + msc_desc[13] = LOBYTE(mp); + msc_desc[14] = HIBYTE(mp); + msc_desc[20] = LOBYTE(mp); + msc_desc[21] = HIBYTE(mp); + } + #endif + *length = usbd->usbd_config_desc_size; return usbd->usbd_config_desc; } -// this is used only in high-speed mode, which we don't support uint8_t *USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - /* + #if USBD_SUPPORT_HS_MODE *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc); return USBD_CDC_MSC_HID_DeviceQualifierDesc; - */ + #else *length = 0; return NULL; + #endif } // data received on non-control OUT endpoint -uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, const uint8_t *buf) { - if (usbd->CDC_ClassData.TxState == 0) { +uint8_t USBD_CDC_TransmitPacket(usbd_cdc_state_t *cdc, size_t len, const uint8_t *buf) { + if (cdc->tx_in_progress == 0) { // transmit next packet - USBD_LL_Transmit(usbd->pdev, CDC_IN_EP, (uint8_t*)buf, len); + USBD_LL_Transmit(cdc->usbd->pdev, cdc->in_ep, (uint8_t*)buf, len); // Tx transfer in progress - usbd->CDC_ClassData.TxState = 1; + cdc->tx_in_progress = 1; return USBD_OK; } else { return USBD_BUSY; @@ -974,60 +1230,67 @@ uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, cons } // prepare OUT endpoint for reception -uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { +uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) { // Suspend or Resume USB Out process - if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) { + + #if !USBD_SUPPORT_HS_MODE + if (cdc->usbd->pdev->dev_speed == USBD_SPEED_HIGH) { return USBD_FAIL; } + #endif // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(usbd->pdev, CDC_OUT_EP, buf, CDC_DATA_OUT_PACKET_SIZE); + USBD_LL_PrepareReceive(cdc->usbd->pdev, cdc->out_ep, buf, usbd_cdc_max_packet(cdc->usbd->pdev)); return USBD_OK; } // prepare OUT endpoint for reception -uint8_t USBD_HID_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { +uint8_t USBD_HID_ReceivePacket(usbd_hid_state_t *hid, uint8_t *buf) { // Suspend or Resume USB Out process - if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) { + + #if !USBD_SUPPORT_HS_MODE + if (hid->usbd->pdev->dev_speed == USBD_SPEED_HIGH) { return USBD_FAIL; } + #endif // Prepare Out endpoint to receive next packet uint16_t mps_out = - usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] - | (usbd->hid_desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); - USBD_LL_PrepareReceive(usbd->pdev, usbd->hid_out_ep, buf, mps_out); + hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_LO] + | (hid->desc[HID_DESC_OFFSET_MAX_PACKET_OUT_HI] << 8); + USBD_LL_PrepareReceive(hid->usbd->pdev, hid->out_ep, buf, mps_out); return USBD_OK; } -int USBD_HID_CanSendReport(usbd_cdc_msc_hid_state_t *usbd) { - return usbd->pdev->dev_state == USBD_STATE_CONFIGURED && usbd->HID_ClassData.state == HID_IDLE; +int USBD_HID_CanSendReport(usbd_hid_state_t *hid) { + return hid->usbd->pdev->dev_state == USBD_STATE_CONFIGURED && hid->state == HID_IDLE; } -uint8_t USBD_HID_SendReport(usbd_cdc_msc_hid_state_t *usbd, uint8_t *report, uint16_t len) { - if (usbd->pdev->dev_state == USBD_STATE_CONFIGURED) { - if (usbd->HID_ClassData.state == HID_IDLE) { - usbd->HID_ClassData.state = HID_BUSY; - USBD_LL_Transmit(usbd->pdev, usbd->hid_in_ep, report, len); +uint8_t USBD_HID_SendReport(usbd_hid_state_t *hid, uint8_t *report, uint16_t len) { + if (hid->usbd->pdev->dev_state == USBD_STATE_CONFIGURED) { + if (hid->state == HID_IDLE) { + hid->state = HID_BUSY; + USBD_LL_Transmit(hid->usbd->pdev, hid->in_ep, report, len); + return USBD_OK; } } - return USBD_OK; + return USBD_FAIL; } -uint8_t USBD_HID_SetNAK(usbd_cdc_msc_hid_state_t *usbd) { +uint8_t USBD_HID_SetNAK(usbd_hid_state_t *hid) { // get USBx object from pdev (needed for USBx_OUTEP macro below) - PCD_HandleTypeDef *hpcd = usbd->pdev->pData; + PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; // set NAK on HID OUT endpoint USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK; return USBD_OK; } -uint8_t USBD_HID_ClearNAK(usbd_cdc_msc_hid_state_t *usbd) { +uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *hid) { // get USBx object from pdev (needed for USBx_OUTEP macro below) - PCD_HandleTypeDef *hpcd = usbd->pdev->pData; + PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; // clear NAK on HID OUT endpoint USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; @@ -1051,3 +1314,5 @@ const USBD_ClassTypeDef USBD_CDC_MSC_HID = { USBD_CDC_MSC_HID_GetCfgDesc, USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor, }; + +#endif diff --git a/ports/stm32/usbdev/class/src/usbd_msc_bot.c b/ports/stm32/usbdev/class/src/usbd_msc_bot.c index 2fccd9e082..d20f7a8dc0 100644 --- a/ports/stm32/usbdev/class/src/usbd_msc_bot.c +++ b/ports/stm32/usbdev/class/src/usbd_msc_bot.c @@ -1,407 +1,407 @@ -/** - ****************************************************************************** - * @file usbd_msc_bot.c - * @author MCD Application Team - * @version V2.0.0 - * @date 18-February-2014 - * @brief This file provides all the BOT protocol core functions. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

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

 

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

Back to Release page

-
-

Release Notes for STM32 USB Host Library

-

Copyright - 2014 STMicroelectronics

-

-
-

 

- - - - -
-

Update History

- -

V3.0.0 / 18-February-2014

- - - -

Main -Changes

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

V2.1.0 / 19-March-2012

-

Main -Changes

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

V2.0.0 / 22-July-2011

Main -Changes

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

V1.0.0 - 11/29/2010

-
  • Created 

License

-

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


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

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

-
-

-
- -
- -

 

- -
- - \ No newline at end of file diff --git a/ports/stm32/usrsw.c b/ports/stm32/usrsw.c index a7721ad779..ded0b68640 100644 --- a/ports/stm32/usrsw.c +++ b/ports/stm32/usrsw.c @@ -30,7 +30,6 @@ #include "py/mphal.h" #include "extint.h" #include "pin.h" -#include "genhdr/pins.h" #include "usrsw.h" #if MICROPY_HW_HAS_SWITCH @@ -54,11 +53,11 @@ // this function inits the switch GPIO so that it can be used void switch_init0(void) { - mp_hal_pin_config(&MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0); + mp_hal_pin_config(MICROPY_HW_USRSW_PIN, MP_HAL_PIN_MODE_INPUT, MICROPY_HW_USRSW_PULL, 0); } int switch_get(void) { - int val = ((MICROPY_HW_USRSW_PIN.gpio->IDR & MICROPY_HW_USRSW_PIN.pin_mask) != 0); + int val = ((MICROPY_HW_USRSW_PIN->gpio->IDR & MICROPY_HW_USRSW_PIN->pin_mask) != 0); return val == MICROPY_HW_USRSW_PRESSED; } @@ -119,7 +118,7 @@ mp_obj_t pyb_switch_callback(mp_obj_t self_in, mp_obj_t callback) { // Init the EXTI each time this function is called, since the EXTI // may have been disabled by an exception in the interrupt, or the // user disabling the line explicitly. - extint_register((mp_obj_t)&MICROPY_HW_USRSW_PIN, + extint_register((mp_obj_t)MICROPY_HW_USRSW_PIN, MICROPY_HW_USRSW_EXTI_MODE, MICROPY_HW_USRSW_PULL, callback == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj, diff --git a/ports/stm32/usrsw.h b/ports/stm32/usrsw.h index d96e3c2813..a8a087db2f 100644 --- a/ports/stm32/usrsw.h +++ b/ports/stm32/usrsw.h @@ -23,12 +23,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USRSW_H -#define MICROPY_INCLUDED_STMHAL_USRSW_H +#ifndef MICROPY_INCLUDED_STM32_USRSW_H +#define MICROPY_INCLUDED_STM32_USRSW_H void switch_init0(void); int switch_get(void); extern const mp_obj_type_t pyb_switch_type; -#endif // MICROPY_INCLUDED_STMHAL_USRSW_H +#endif // MICROPY_INCLUDED_STM32_USRSW_H diff --git a/ports/stm32/wdt.c b/ports/stm32/wdt.c index 2b4967a434..8df7b47684 100644 --- a/ports/stm32/wdt.c +++ b/ports/stm32/wdt.c @@ -29,6 +29,10 @@ #include "py/runtime.h" #include "wdt.h" +#if defined(STM32H7) +#define IWDG (IWDG1) +#endif + typedef struct _pyb_wdt_obj_t { mp_obj_base_t base; } pyb_wdt_obj_t; diff --git a/ports/stm32/wdt.h b/ports/stm32/wdt.h index 0a486f704d..d60bb7e9e6 100644 --- a/ports/stm32/wdt.h +++ b/ports/stm32/wdt.h @@ -23,9 +23,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_WDT_H -#define MICROPY_INCLUDED_STMHAL_WDT_H +#ifndef MICROPY_INCLUDED_STM32_WDT_H +#define MICROPY_INCLUDED_STM32_WDT_H extern const mp_obj_type_t pyb_wdt_type; -#endif // MICROPY_INCLUDED_STMHAL_WDT_H +#endif // MICROPY_INCLUDED_STM32_WDT_H diff --git a/ports/teensy/hal_gpio.c b/ports/teensy/hal_gpio.c index e65d03410e..f9e137602c 100644 --- a/ports/teensy/hal_gpio.c +++ b/ports/teensy/hal_gpio.c @@ -52,7 +52,7 @@ void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) *port_pcr |= PORT_PCR_DSE; /* Configure the IO Speed */ - if (GPIO_Init->Speed > GPIO_SPEED_MEDIUM) { + if (GPIO_Init->Speed > GPIO_SPEED_FREQ_MEDIUM) { *port_pcr &= ~PORT_PCR_SRE; } else { *port_pcr |= PORT_PCR_SRE; diff --git a/ports/teensy/led.c b/ports/teensy/led.c index add052fad2..cf59dbd0a3 100644 --- a/ports/teensy/led.c +++ b/ports/teensy/led.c @@ -33,7 +33,7 @@ void led_init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* Configure I/O speed, mode, output type and pull */ - GPIO_InitStructure.Speed = GPIO_SPEED_LOW; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Mode = MICROPY_HW_LED_OTYPE; GPIO_InitStructure.Pull = GPIO_NOPULL; diff --git a/ports/teensy/mk20dx256_prefix.c b/ports/teensy/mk20dx256_prefix.c index d8e7480b58..58ab07d6ec 100644 --- a/ports/teensy/mk20dx256_prefix.c +++ b/ports/teensy/mk20dx256_prefix.c @@ -15,7 +15,7 @@ .fn = AF_FN_ ## af_fn, \ .unit = (af_unit), \ .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ - .af_fn = (af_ptr) \ + .reg = (af_ptr) \ } #define PIN(p_port, p_pin, p_num_af, p_af, p_adc_num, p_adc_channel) \ diff --git a/ports/teensy/pin_defs_teensy.h b/ports/teensy/pin_defs_teensy.h index 54a6055f1a..d3a700be21 100644 --- a/ports/teensy/pin_defs_teensy.h +++ b/ports/teensy/pin_defs_teensy.h @@ -40,10 +40,4 @@ enum { AF_PIN_TYPE_UART_RTS, }; -#define PIN_DEFS_PORT_AF_UNION \ - FTM_TypeDef *FTM; \ - I2C_TypeDef *I2C; \ - UART_TypeDef *UART; \ - SPI_TypeDef *SPI; - typedef GPIO_TypeDef pin_gpio_t; diff --git a/ports/teensy/teensy_hal.h b/ports/teensy/teensy_hal.h index 162effa85c..aef38a2ad9 100644 --- a/ports/teensy/teensy_hal.h +++ b/ports/teensy/teensy_hal.h @@ -74,10 +74,10 @@ typedef struct { #define IS_GPIO_PULL(PULL) (((PULL) == GPIO_NOPULL) || ((PULL) == GPIO_PULLUP) || \ ((PULL) == GPIO_PULLDOWN)) -#define GPIO_SPEED_LOW ((uint32_t)0) -#define GPIO_SPEED_MEDIUM ((uint32_t)1) -#define GPIO_SPEED_FAST ((uint32_t)2) -#define GPIO_SPEED_HIGH ((uint32_t)3) +#define GPIO_SPEED_FREQ_LOW ((uint32_t)0) +#define GPIO_SPEED_FREQ_MEDIUM ((uint32_t)1) +#define GPIO_SPEED_FREQ_HIGH ((uint32_t)2) +#define GPIO_SPEED_FREQ_VERY_HIGH ((uint32_t)3) #define IS_GPIO_AF(af) ((af) >= 0 && (af) <= 7) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index dacf680195..1136c42b62 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -165,7 +165,6 @@ LIB_SRC_C += $(addprefix lib/,\ OBJ = $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(STMHAL_SRC_C:.c=.o)) # List of sources for qstr extraction SRC_QSTR += $(SRC_C) $(LIB_SRC_C) @@ -243,7 +242,7 @@ freedos: # build an interpreter for coverage testing and do the testing coverage: $(MAKE) V=2 \ - COPT="-O0" CFLAGS_EXTRA='-DMP_CONFIGFILE="\"mpconfigport_coverage.h\"" \ + COPT="-O0" CFLAGS_EXTRA='$(CFLAGS_EXTRA) -DMP_CONFIGFILE="" \ -fprofile-arcs -ftest-coverage \ -Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wsign-compare \ -Wold-style-definition -Wpointer-arith -Wshadow -Wuninitialized -Wunused-parameter \ @@ -258,6 +257,7 @@ coverage_test: coverage cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --auto-jobs -d thread cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --auto-jobs --emit native cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -j1 --via-mpy -d basics float + cat $(TOP)/tests/basics/0prelim.py | ./micropython_coverage | grep -q 'abc' gcov -o build-coverage/py $(TOP)/py/*.c gcov -o build-coverage/extmod $(TOP)/extmod/*.c diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 651db0a943..7820f6d736 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -4,6 +4,7 @@ #include "py/obj.h" #include "py/objstr.h" #include "py/runtime.h" +#include "py/gc.h" #include "py/repl.h" #include "py/mpz.h" #include "py/builtin.h" @@ -11,6 +12,7 @@ #include "py/formatfloat.h" #include "py/stream.h" #include "py/binary.h" +#include "py/bc.h" #if defined(MICROPY_UNIX_COVERAGE) @@ -116,7 +118,6 @@ STATIC mp_uint_t stest_read2(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc STATIC const mp_rom_map_elem_t rawfile_locals_dict_table2[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, }; STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict2, rawfile_locals_dict_table2); @@ -145,11 +146,16 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding mp_printf(&mp_plat_print, "%ld\n", 123); // long + mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex mp_printf(&mp_plat_print, "%.2s %.3s\n", "abc", "abc"); // fixed string precision mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools + #ifndef NDEBUG mp_printf(&mp_plat_print, "%s\n", NULL); // null string + #else + mp_printf(&mp_plat_print, "(null)\n"); // without debugging mp_printf won't check for null + #endif mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned @@ -157,6 +163,23 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier } + // GC + { + mp_printf(&mp_plat_print, "# GC\n"); + + // calling gc_free while GC is locked + gc_lock(); + gc_free(NULL); + gc_unlock(); + + // using gc_realloc to resize to 0, which means free the memory + void *p = gc_alloc(4, false); + mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false)); + + // calling gc_nbytes with a non-heap pointer + mp_printf(&mp_plat_print, "%p\n", gc_nbytes(NULL)); + } + // vstr { mp_printf(&mp_plat_print, "# vstr\n"); @@ -227,7 +250,17 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# str\n"); // intern string - mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9, false)))); + mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); + } + + // bytearray + { + mp_printf(&mp_plat_print, "# bytearray\n"); + + // create a bytearray via mp_obj_new_bytearray + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(mp_obj_new_bytearray(4, "data"), &bufinfo, MP_BUFFER_RW); + mp_printf(&mp_plat_print, "%.*s\n", bufinfo.len, bufinfo.buf); } // mpz @@ -251,6 +284,39 @@ STATIC mp_obj_t extra_coverage(void) { mpz_set_from_int(&mpz, 1); mpz_shl_inpl(&mpz, &mpz, 70); mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value)); + + // mpz_set_from_float with inf as argument + mpz_set_from_float(&mpz, 1.0 / 0.0); + mpz_as_uint_checked(&mpz, &value); + mp_printf(&mp_plat_print, "%d\n", (int)value); + + // mpz_set_from_float with 0 as argument + mpz_set_from_float(&mpz, 0); + mpz_as_uint_checked(&mpz, &value); + mp_printf(&mp_plat_print, "%d\n", (int)value); + + // mpz_set_from_float with 0fun_bc = &fun_bc; + code_state->ip = (const byte*)"\x00"; // just needed for an invalid opcode + code_state->sp = &code_state->state[0]; + code_state->exc_sp = NULL; + code_state->old_globals = NULL; + mp_vm_return_kind_t ret = mp_execute_bytecode(code_state, MP_OBJ_NULL); + mp_printf(&mp_plat_print, "%d %d\n", ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError); + } + // scheduler { mp_printf(&mp_plat_print, "# scheduler\n"); diff --git a/ports/unix/file.c b/ports/unix/file.c index 84e9180821..165bbd00b0 100644 --- a/ports/unix/file.c +++ b/ports/unix/file.c @@ -37,7 +37,7 @@ #include "py/mphal.h" #include "fdfile.h" -#if MICROPY_PY_IO +#if MICROPY_PY_IO && !MICROPY_VFS #ifdef _WIN32 #define fsync _commit @@ -118,25 +118,21 @@ STATIC mp_uint_t fdfile_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i return MP_STREAM_ERROR; } return 0; + case MP_STREAM_CLOSE: + close(o->fd); + #ifdef MICROPY_CPYTHON_COMPAT + o->fd = -1; + #endif + return 0; default: *errcode = EINVAL; return MP_STREAM_ERROR; } } -STATIC mp_obj_t fdfile_close(mp_obj_t self_in) { - mp_obj_fdfile_t *self = MP_OBJ_TO_PTR(self_in); - close(self->fd); -#ifdef MICROPY_CPYTHON_COMPAT - self->fd = -1; -#endif - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_close_obj, fdfile_close); - STATIC mp_obj_t fdfile___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - return fdfile_close(args[0]); + return mp_stream_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fdfile___exit___obj, 4, 4, fdfile___exit__); @@ -224,7 +220,7 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&fdfile_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&fdfile___exit___obj) }, }; @@ -281,4 +277,4 @@ const mp_obj_fdfile_t mp_sys_stdin_obj = { .base = {&mp_type_textio}, .fd = STD const mp_obj_fdfile_t mp_sys_stdout_obj = { .base = {&mp_type_textio}, .fd = STDOUT_FILENO }; const mp_obj_fdfile_t mp_sys_stderr_obj = { .base = {&mp_type_textio}, .fd = STDERR_FILENO }; -#endif // MICROPY_PY_IO +#endif // MICROPY_PY_IO && !MICROPY_VFS diff --git a/ports/unix/main.c b/ports/unix/main.c index 629e36b8b3..d1187ae905 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -47,6 +47,8 @@ #include "py/mphal.h" #include "py/mpthread.h" #include "extmod/misc.h" +#include "extmod/vfs.h" +#include "extmod/vfs_posix.h" #include "genhdr/mpversion.h" #include "input.h" @@ -441,8 +443,25 @@ MP_NOINLINE int main_(int argc, char **argv) { gc_init(heap, heap + heap_size); #endif + #if MICROPY_ENABLE_PYSTACK + static mp_obj_t pystack[1024]; + mp_pystack_init(pystack, &pystack[MP_ARRAY_SIZE(pystack)]); + #endif + mp_init(); + #if MICROPY_VFS_POSIX + { + // Mount the host FS at the root of our internal VFS + mp_obj_t args[2] = { + mp_type_vfs_posix.make_new(&mp_type_vfs_posix, 0, 0, NULL), + MP_OBJ_NEW_QSTR(MP_QSTR__slash_), + }; + mp_vfs_mount(2, args, (mp_map_t*)&mp_const_empty_map); + MP_STATE_VM(vfs_cur) = MP_STATE_VM(vfs_mount_table); + } + #endif + char *home = getenv("HOME"); char *path = getenv("MICROPYPATH"); if (path == NULL) { @@ -486,7 +505,7 @@ MP_NOINLINE int main_(int argc, char **argv) { vstr_add_strn(&vstr, p + 1, p1 - p - 1); path_items[i] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } else { - path_items[i] = MP_OBJ_NEW_QSTR(qstr_from_strn(p, p1 - p)); + path_items[i] = mp_obj_new_str_via_qstr(p, p1 - p); } p = p1 + 1; } @@ -545,7 +564,7 @@ MP_NOINLINE int main_(int argc, char **argv) { return usage(argv); } mp_obj_t import_args[4]; - import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1]), false); + import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1])); import_args[1] = import_args[2] = mp_const_none; // Ask __import__ to handle imported module specially - set its __name__ // to __main__, and also return this leaf module, not top-level package @@ -611,7 +630,7 @@ MP_NOINLINE int main_(int argc, char **argv) { // Set base dir of the script as first entry in sys.path char *p = strrchr(basedir, '/'); - path_items[0] = MP_OBJ_NEW_QSTR(qstr_from_strn(basedir, p - basedir)); + path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir); free(pathbuf); set_sys_argv(argv, argc, a); @@ -636,6 +655,10 @@ MP_NOINLINE int main_(int argc, char **argv) { } #endif + #if defined(MICROPY_UNIX_COVERAGE) + gc_sweep_all(); + #endif + mp_deinit(); #if MICROPY_ENABLE_GC && !defined(NDEBUG) @@ -648,6 +671,7 @@ MP_NOINLINE int main_(int argc, char **argv) { return ret & 0xff; } +#if !MICROPY_VFS uint mp_import_stat(const char *path) { struct stat st; if (stat(path, &st) == 0) { @@ -659,6 +683,7 @@ uint mp_import_stat(const char *path) { } return MP_IMPORT_STAT_NO_EXIST; } +#endif void nlr_jump_fail(void *val) { printf("FATAL: uncaught NLR %p\n", val); diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index 1c04c4deff..a12c249e21 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -144,7 +144,7 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) if (!s) { return mp_const_none; } - return mp_obj_new_str(s, strlen(s), false); + return mp_obj_new_str(s, strlen(s)); } case 'v': return mp_const_none; diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c index f29c095cf5..8ec5ae54d9 100644 --- a/ports/unix/modjni.c +++ b/ports/unix/modjni.c @@ -337,7 +337,7 @@ STATIC mp_obj_t new_jobject(jobject jo) { return mp_const_none; } else if (JJ(IsInstanceOf, jo, String_class)) { const char *s = JJ(GetStringUTFChars, jo, NULL); - mp_obj_t ret = mp_obj_new_str(s, strlen(s), false); + mp_obj_t ret = mp_obj_new_str(s, strlen(s)); JJ(ReleaseStringUTFChars, jo, s); return ret; } else if (JJ(IsInstanceOf, jo, Class_class)) { diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 327116a0a6..d99d0d62c9 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -126,16 +126,16 @@ STATIC mp_obj_t mod_os_system(mp_obj_t cmd_in) { return MP_OBJ_NEW_SMALL_INT(r); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_system_obj, mod_os_system); +MP_DEFINE_CONST_FUN_OBJ_1(mod_os_system_obj, mod_os_system); STATIC mp_obj_t mod_os_getenv(mp_obj_t var_in) { const char *s = getenv(mp_obj_str_get_str(var_in)); if (s == NULL) { return mp_const_none; } - return mp_obj_new_str(s, strlen(s), false); + return mp_obj_new_str(s, strlen(s)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv); +MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv); STATIC mp_obj_t mod_os_mkdir(mp_obj_t path_in) { // TODO: Accept mode param @@ -171,7 +171,7 @@ STATIC mp_obj_t listdir_next(mp_obj_t self_in) { } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); - t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name), false); + t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name)); #ifdef _DIRENT_HAVE_D_TYPE t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type); #else @@ -207,7 +207,7 @@ STATIC mp_obj_t mod_os_errno(size_t n_args, const mp_obj_t *args) { errno = mp_obj_get_int(args[0]); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj, 0, 1, mod_os_errno); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj, 0, 1, mod_os_errno); STATIC const mp_rom_map_elem_t mp_module_os_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, diff --git a/ports/unix/moduos_vfs.c b/ports/unix/moduos_vfs.c index 96defa5544..e9ac8e1f88 100644 --- a/ports/unix/moduos_vfs.c +++ b/ports/unix/moduos_vfs.c @@ -28,17 +28,26 @@ #include #include "extmod/vfs.h" +#include "extmod/vfs_posix.h" #include "extmod/vfs_fat.h" #if MICROPY_VFS +// These are defined in modos.c +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_errno_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_os_getenv_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_os_system_obj); + STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos_vfs) }, { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) }, + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mod_os_errno_obj) }, + { MP_ROM_QSTR(MP_QSTR_getenv), MP_ROM_PTR(&mod_os_getenv_obj) }, + { MP_ROM_QSTR(MP_QSTR_system), MP_ROM_PTR(&mod_os_system_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) }, - { MP_ROM_QSTR(MP_QSTR_vfs_open), MP_ROM_PTR(&mp_vfs_open_obj) }, { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, @@ -52,6 +61,13 @@ STATIC const mp_rom_map_elem_t uos_vfs_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) }, { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove + #if MICROPY_PY_OS_DUPTERM + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + #endif + + #if MICROPY_VFS_POSIX + { MP_ROM_QSTR(MP_QSTR_VfsPosix), MP_ROM_PTR(&mp_type_vfs_posix) }, + #endif #if MICROPY_VFS_FAT { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, #endif diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c index ba1c195ef4..1ea7dc19a5 100644 --- a/ports/unix/moduselect.c +++ b/ports/unix/moduselect.c @@ -40,6 +40,8 @@ #include "py/mphal.h" #include "fdfile.h" +#define DEBUG 0 + #if MICROPY_PY_SOCKET extern const mp_obj_type_t mp_type_socket; #endif @@ -277,12 +279,34 @@ STATIC mp_obj_t poll_iternext(mp_obj_t self_in) { return MP_OBJ_STOP_ITERATION; } +#if DEBUG +STATIC mp_obj_t poll_dump(mp_obj_t self_in) { + mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); + + struct pollfd *entries = self->entries; + for (int i = self->len - 1; i >= 0; i--) { + printf("fd: %d ev: %x rev: %x", entries->fd, entries->events, entries->revents); + if (self->obj_map) { + printf(" obj: %p", self->obj_map[entries - self->entries]); + } + printf("\n"); + entries++; + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(poll_dump_obj, poll_dump); +#endif + STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) }, { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) }, { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) }, { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) }, { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) }, + #if DEBUG + { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&poll_dump_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table); diff --git a/ports/unix/modusocket.c b/ports/unix/modusocket.c index cfb6a9f5ec..ba50e6165e 100644 --- a/ports/unix/modusocket.c +++ b/ports/unix/modusocket.c @@ -108,19 +108,26 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in return r; } -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); - // There's a POSIX drama regarding return value of close in general, - // and EINTR error in particular. See e.g. - // http://lwn.net/Articles/576478/ - // http://austingroupbugs.net/view.php?id=529 - // The rationale MicroPython follows is that close() just releases - // file descriptor. If you're interested to catch I/O errors before - // closing fd, fsync() it. - close(self->fd); - return mp_const_none; +STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_socket_t *self = MP_OBJ_TO_PTR(o_in); + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + // There's a POSIX drama regarding return value of close in general, + // and EINTR error in particular. See e.g. + // http://lwn.net/Articles/576478/ + // http://austingroupbugs.net/view.php?id=529 + // The rationale MicroPython follows is that close() just releases + // file descriptor. If you're interested to catch I/O errors before + // closing fd, fsync() it. + close(self->fd); + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); STATIC mp_obj_t socket_fileno(mp_obj_t self_in) { mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in); @@ -359,7 +366,7 @@ STATIC const mp_rom_map_elem_t usocket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(usocket_locals_dict, usocket_locals_dict_table); @@ -367,6 +374,7 @@ STATIC MP_DEFINE_CONST_DICT(usocket_locals_dict, usocket_locals_dict_table); STATIC const mp_stream_p_t usocket_stream_p = { .read = socket_read, .write = socket_write, + .ioctl = socket_ioctl, }; const mp_obj_type_t mp_type_socket = { diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index db382e0a71..e0f9d99957 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -83,6 +83,7 @@ #define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1) #define MICROPY_PY_BUILTINS_INPUT (1) #define MICROPY_PY_BUILTINS_POW3 (1) +#define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) @@ -97,18 +98,21 @@ #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) #endif #define MICROPY_PY_CMATH (1) +#define MICROPY_PY_IO_IOBASE (1) #define MICROPY_PY_IO_FILEIO (1) -#define MICROPY_PY_IO_RESOURCE_STREAM (1) #define MICROPY_PY_GC_COLLECT_RETVAL (1) #define MICROPY_MODULE_FROZEN_STR (1) +#ifndef MICROPY_STACKLESS #define MICROPY_STACKLESS (0) #define MICROPY_STACKLESS_STRICT (0) +#endif #define MICROPY_PY_OS_STATVFS (1) #define MICROPY_PY_UTIME (1) @@ -121,7 +125,7 @@ #define MICROPY_PY_UHEAPQ (1) #define MICROPY_PY_UTIMEQ (1) #define MICROPY_PY_UHASHLIB (1) -#if MICROPY_PY_USSL && MICROPY_SSL_AXTLS +#if MICROPY_PY_USSL #define MICROPY_PY_UHASHLIB_SHA1 (1) #endif #define MICROPY_PY_UBINASCII (1) @@ -177,9 +181,9 @@ extern const struct _mp_obj_module_t mp_module_ffi; extern const struct _mp_obj_module_t mp_module_jni; #if MICROPY_PY_UOS_VFS -#define MICROPY_PY_UOS_VFS_DEF { MP_ROM_QSTR(MP_QSTR_uos_vfs), MP_ROM_PTR(&mp_module_uos_vfs) }, +#define MICROPY_PY_UOS_DEF { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_uos_vfs) }, #else -#define MICROPY_PY_UOS_VFS_DEF +#define MICROPY_PY_UOS_DEF { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, #endif #if MICROPY_PY_FFI #define MICROPY_PY_FFI_DEF { MP_ROM_QSTR(MP_QSTR_ffi), MP_ROM_PTR(&mp_module_ffi) }, @@ -218,8 +222,7 @@ extern const struct _mp_obj_module_t mp_module_jni; MICROPY_PY_UTIME_DEF \ MICROPY_PY_SOCKET_DEF \ { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&mp_module_machine) }, \ - { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&mp_module_os) }, \ - MICROPY_PY_UOS_VFS_DEF \ + MICROPY_PY_UOS_DEF \ MICROPY_PY_USELECT_DEF \ MICROPY_PY_TERMIOS_DEF \ diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index 86d95eb39b..97c05cfee4 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -34,14 +34,28 @@ #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) #define MICROPY_ENABLE_SCHEDULER (1) +#define MICROPY_READER_VFS (1) #define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_RANGE_BINOP (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_MODULES (1) #define MICROPY_PY_SYS_GETSIZEOF (1) #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) #define MICROPY_PY_IO_BUFFEREDWRITER (1) +#define MICROPY_PY_IO_RESOURCE_STREAM (1) +#define MICROPY_VFS_POSIX (1) #undef MICROPY_VFS_FAT #define MICROPY_VFS_FAT (1) #define MICROPY_FATFS_USE_LABEL (1) #define MICROPY_PY_FRAMEBUF (1) +#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (1) + +// TODO these should be generic, not bound to fatfs +#define mp_type_fileio mp_type_vfs_posix_fileio +#define mp_type_textio mp_type_vfs_posix_textio + +// use vfs's functions for import stat and builtin open +#define mp_import_stat mp_vfs_import_stat +#define mp_builtin_open mp_vfs_open +#define mp_builtin_open_obj mp_vfs_open_obj diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 8c636a4457..baca0a2b1e 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -66,6 +66,10 @@ STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) { // that we don't need the extra information, enough is captured by the // gc_collect_regs_and_stack function above //gc_collect_root((void**)context, sizeof(ucontext_t) / sizeof(uintptr_t)); + #if MICROPY_ENABLE_PYSTACK + void **ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start); + gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*)); + #endif thread_signal_done = 1; } } diff --git a/ports/windows/Makefile b/ports/windows/Makefile index b6433300fe..725cb686e5 100644 --- a/ports/windows/Makefile +++ b/ports/windows/Makefile @@ -50,10 +50,6 @@ CFLAGS_MOD += -DMICROPY_USE_READLINE=2 LDFLAGS_MOD += -lreadline endif -ifeq ($(CROSS_COMPILE),x86_64-w64-mingw32-) -CFLAGS_MOD += -DMICROPY_NLR_SETJMP=1 -endif - LIB += -lws2_32 # List of sources for qstr extraction diff --git a/ports/windows/mpconfigport.h b/ports/windows/mpconfigport.h index abad352825..9db6d31ce8 100644 --- a/ports/windows/mpconfigport.h +++ b/ports/windows/mpconfigport.h @@ -41,6 +41,7 @@ #define MICROPY_COMP_RETURN_IF_EXPR (1) #define MICROPY_ENABLE_GC (1) #define MICROPY_ENABLE_FINALISER (1) +#define MICROPY_ENABLE_PYSTACK (1) #define MICROPY_STACK_CHECK (1) #define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1) #define MICROPY_MEM_STATS (1) @@ -56,6 +57,7 @@ #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_STREAMS_POSIX_API (1) #define MICROPY_OPT_COMPUTED_GOTO (0) #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) @@ -73,6 +75,7 @@ #define MICROPY_PY_BUILTINS_POW3 (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_SYS_EXIT (1) @@ -80,6 +83,7 @@ #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_SYS_EXC_INFO (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) #define MICROPY_PY_CMATH (1) @@ -109,9 +113,12 @@ #define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +#define MICROPY_ERROR_PRINTER (&mp_stderr_print) #define MICROPY_WARNINGS (1) #define MICROPY_PY_STR_BYTES_CMP_WARN (1) +extern const struct _mp_print_t mp_stderr_print; + #ifdef _MSC_VER #define MICROPY_GCREGS_SETJMP (1) #endif @@ -232,6 +239,7 @@ typedef __int64 ssize_t; #define SSIZE_MAX _I32_MAX typedef int ssize_t; #endif +typedef mp_off_t off_t; // Put static/global variables in sections with a known name diff --git a/ports/zephyr/CMakeLists.txt b/ports/zephyr/CMakeLists.txt new file mode 100644 index 0000000000..84b0e8190a --- /dev/null +++ b/ports/zephyr/CMakeLists.txt @@ -0,0 +1,21 @@ +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +target_sources(app PRIVATE src/zephyr_start.c src/zephyr_getchar.c) + +add_library(libmicropython STATIC IMPORTED) +set_target_properties(libmicropython PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libmicropython.a) +target_link_libraries(app libmicropython) + +zephyr_get_include_directories_for_lang_as_string(C includes) +zephyr_get_system_include_directories_for_lang_as_string(C system_includes) +zephyr_get_compile_definitions_for_lang_as_string(C definitions) +zephyr_get_compile_options_for_lang_as_string(C options) + +add_custom_target( + outputexports + COMMAND echo CC="${CMAKE_C_COMPILER}" + COMMAND echo Z_CFLAGS=${system_includes} ${includes} ${definitions} ${options} + VERBATIM + USES_TERMINAL +) diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 2e6cb41b98..8cb4c12ef7 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -20,15 +20,15 @@ FROZEN_DIR = scripts # Default target all: +include ../../py/mkenv.mk +include $(TOP)/py/py.mk + # Zephyr (generated) config files - must be defined before include below Z_EXPORTS = outdir/$(OUTDIR_PREFIX)/Makefile.export ifneq ($(MAKECMDGOALS), clean) include $(Z_EXPORTS) endif -include ../../py/mkenv.mk -include $(TOP)/py/py.mk - INC += -I. INC += -I$(TOP) INC += -I$(BUILD) @@ -41,6 +41,7 @@ SRC_C = main.c \ modusocket.c \ modutime.c \ modzephyr.c \ + modzsensor.c \ modmachine.c \ machine_pin.c \ uart_core.c \ @@ -56,19 +57,11 @@ SRC_QSTR += $(SRC_C) OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -CFLAGS = $(KBUILD_CFLAGS) $(NOSTDINC_FLAGS) $(ZEPHYRINCLUDE) \ +CFLAGS = $(Z_CFLAGS) \ -std=gnu99 -fomit-frame-pointer -DNDEBUG -DMICROPY_HEAP_SIZE=$(MICROPY_HEAP_SIZE) $(CFLAGS_EXTRA) $(INC) include $(TOP)/py/mkrules.mk -# We use single target here ($(Z_EXPORTS)) for simplicity, but actually -# number of things get generated here: 'initconfig' generates C header for -# Kconfig configuration, 'outputexports' generates make environment with CC, -# etc., and 'lib' generates other headers which may be included by zephyr.h, -# e.g. DTS-related. -$(Z_EXPORTS): $(CONF_FILE) - $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) initconfig outputexports lib - GENERIC_TARGETS = all zephyr run qemu qemugdb flash debug debugserver KCONFIG_TARGETS = \ initconfig config nconfig menuconfig xconfig gconfig \ @@ -81,7 +74,7 @@ $(GENERIC_TARGETS): $(LIBMICROPYTHON) $(CLEAN_TARGETS): clean $(GENERIC_TARGETS) $(KCONFIG_TARGETS) $(CLEAN_TARGETS): - $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) $@ + $(MAKE) -C outdir/$(BOARD) $@ $(LIBMICROPYTHON): | $(Z_EXPORTS) build/genhdr/qstr.i.last: | $(Z_EXPORTS) @@ -90,16 +83,27 @@ build/genhdr/qstr.i.last: | $(Z_EXPORTS) LIBMICROPYTHON_EXTRA_CMD = -$(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk # MicroPython's global clean cleans everything, fast -CLEAN_EXTRA = outdir +CLEAN_EXTRA = outdir libmicropython.a prj_*_merged.conf # Clean Zephyr things in Zephyr way z_clean: $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) clean # This rule is for prj_$(BOARD)_merged.conf, not $(CONF_FILE), which -# can be overriden -prj_$(BOARD)_merged.conf: prj_base.conf prj_$(BOARD).conf +# can be overriden. +# prj_$(BOARD).conf is optional, that's why it's resolved with $(wildcard) +# function. +prj_$(BOARD)_merged.conf: prj_base.conf $(wildcard prj_$(BOARD).conf) $(PYTHON) makeprj.py prj_base.conf prj_$(BOARD).conf $@ test: cd $(TOP)/tests && ./run-tests --target minimal --device "execpty:make -C ../ports/zephyr run BOARD=$(BOARD) QEMU_PTY=1" + +cmake: outdir/$(BOARD)/Makefile + +outdir/$(BOARD)/Makefile: $(CONF_FILE) + mkdir -p outdir/$(BOARD) && cmake -DBOARD=$(BOARD) -DCONF_FILE=$(CONF_FILE) -Boutdir/$(BOARD) -H. + +$(Z_EXPORTS): outdir/$(BOARD)/Makefile + make --no-print-directory -C outdir/$(BOARD) outputexports CMAKE_COMMAND=: >$@ + make -C outdir/$(BOARD) syscall_macros_h_target syscall_list_h_target kobj_types_h_target diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md index 018b4ce715..f7001af4b8 100644 --- a/ports/zephyr/README.md +++ b/ports/zephyr/README.md @@ -46,7 +46,7 @@ Running To run the resulting firmware in QEMU (for BOARDs like qemu_x86, qemu_cortex_m3): - make qemu + make run With the default configuration, networking is now enabled, so you need to follow instructions in https://wiki.zephyrproject.org/view/Networking-with-Qemu @@ -110,4 +110,4 @@ To make a minimal build: To run a minimal build in QEMU without requiring TAP networking setup run the following after you built image with the previous command: - ./make-minimal BOARD= qemu + ./make-minimal BOARD= run diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c index 7eb9da3e12..a28fb37923 100644 --- a/ports/zephyr/main.c +++ b/ports/zephyr/main.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2016 Linaro Limited + * Copyright (c) 2016-2017 Linaro Limited * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,20 +41,12 @@ #include "lib/utils/pyexec.h" #include "lib/mp-readline/readline.h" -void do_str(const char *src, mp_parse_input_kind_t input_kind) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - qstr source_name = lex->source_name; - mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); - mp_call_function_0(module_fun); - nlr_pop(); - } else { - // uncaught exception - mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); - } -} +#ifdef TEST +#include "lib/upytesthelper/upytesthelper.h" +#include "lib/tinytest/tinytest.c" +#include "lib/upytesthelper/upytesthelper.c" +#include TEST +#endif static char *stack_top; static char heap[MICROPY_HEAP_SIZE]; @@ -95,6 +87,13 @@ int real_main(void) { init_zephyr(); + #ifdef TEST + static const char *argv[] = {"test"}; + upytest_set_heap(heap, heap + sizeof(heap)); + int r = tinytest_main(1, argv, groups); + printf("status: %d\n", r); + #endif + soft_reset: #if MICROPY_ENABLE_GC gc_init(heap, heap + sizeof(heap)); diff --git a/ports/zephyr/make-bin-testsuite b/ports/zephyr/make-bin-testsuite new file mode 100755 index 0000000000..f6aeb83f8a --- /dev/null +++ b/ports/zephyr/make-bin-testsuite @@ -0,0 +1,20 @@ +#!/bin/sh +# +# This is a wrapper for make to build a binary with builtin testsuite. +# It should be run just like make (i.e. extra vars can be passed on the +# command line, etc.), e.g.: +# +# ./make-bin-testsuite BOARD=qemu_cortex_m3 +# ./make-bin-testsuite BOARD=qemu_cortex_m3 run +# + +(cd ../../tests; ./run-tests --write-exp) +(cd ../../tests; ./run-tests --list-tests --target=minimal \ + -e async -e intbig -e int_big -e builtin_help -e memstats -e bytes_compare3 -e class_reverse_op \ + -e /set -e frozenset -e complex -e const -e native -e viper \ + -e 'float_divmod\.' -e float_parse_doubleprec -e float/true_value -e float/types \ + | ../tools/tinytest-codegen.py --stdin) > bin-testsuite.c + +make \ + CFLAGS_EXTRA='-DMP_CONFIGFILE="" -DTEST=\"bin-testsuite.c\" -DNO_FORKING' \ + "$@" diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c index e021c3a44f..84d6fa7297 100644 --- a/ports/zephyr/modusocket.c +++ b/ports/zephyr/modusocket.c @@ -91,7 +91,7 @@ STATIC mp_obj_t format_inet_addr(struct sockaddr *addr, mp_obj_t port) { net_addr_ntop(addr->sa_family, &sockaddr_in6->sin6_addr, buf, sizeof(buf)); mp_obj_tuple_t *tuple = mp_obj_new_tuple(addr->sa_family == AF_INET ? 2 : 4, NULL); - tuple->items[0] = mp_obj_new_str(buf, strlen(buf), false); + tuple->items[0] = mp_obj_new_str(buf, strlen(buf)); // We employ the fact that port offset is the same for IPv4 & IPv6 // not filled in //tuple->items[1] = mp_obj_new_int(ntohs(((struct sockaddr_in*)addr)->sin_port)); @@ -299,20 +299,31 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile); -STATIC mp_obj_t socket_close(mp_obj_t self_in) { - socket_obj_t *socket = self_in; - if (socket->ctx != -1) { - int res = zsock_close(socket->ctx); - RAISE_SOCK_ERRNO(res); - socket->ctx = -1; +STATIC mp_uint_t sock_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + socket_obj_t *socket = o_in; + (void)arg; + switch (request) { + case MP_STREAM_CLOSE: + if (socket->ctx != -1) { + int res = zsock_close(socket->ctx); + RAISE_SOCK_ERRNO(res); + if (res == -1) { + *errcode = errno; + return MP_STREAM_ERROR; + } + socket->ctx = -1; + } + return 0; + + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; } - return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, @@ -332,7 +343,7 @@ STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); STATIC const mp_stream_p_t socket_stream_p = { .read = sock_read, .write = sock_write, - //.ioctl = sock_ioctl, + .ioctl = sock_ioctl, }; STATIC const mp_obj_type_t socket_type = { diff --git a/ports/zephyr/modzsensor.c b/ports/zephyr/modzsensor.c new file mode 100644 index 0000000000..74c909d167 --- /dev/null +++ b/ports/zephyr/modzsensor.c @@ -0,0 +1,146 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +#include +#include + +#if MICROPY_PY_ZSENSOR + +typedef struct _mp_obj_sensor_t { + mp_obj_base_t base; + struct device *dev; +} mp_obj_sensor_t; + +STATIC mp_obj_t sensor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_obj_sensor_t *o = m_new_obj(mp_obj_sensor_t); + o->base.type = type; + o->dev = device_get_binding(mp_obj_str_get_str(args[0])); + if (o->dev == NULL) { + mp_raise_ValueError("dev not found"); + } + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t sensor_measure(mp_obj_t self_in) { + mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in); + int st = sensor_sample_fetch(self->dev); + if (st != 0) { + mp_raise_OSError(-st); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(sensor_measure_obj, sensor_measure); + +STATIC void sensor_get_internal(mp_obj_t self_in, mp_obj_t channel_in, struct sensor_value *res) { + mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in); + + int st = sensor_channel_get(self->dev, mp_obj_get_int(channel_in), res); + if (st != 0) { + mp_raise_OSError(-st); + } +} + +STATIC mp_obj_t sensor_get_float(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return mp_obj_new_float(val.val1 + (mp_float_t)val.val2 / 1000000); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_float_obj, sensor_get_float); + +STATIC mp_obj_t sensor_get_micros(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000000 + val.val2); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_micros_obj, sensor_get_micros); + +STATIC mp_obj_t sensor_get_millis(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000 + val.val2 / 1000); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_millis_obj, sensor_get_millis); + +STATIC mp_obj_t sensor_get_int(mp_obj_t self_in, mp_obj_t channel_in) { + struct sensor_value val; + sensor_get_internal(self_in, channel_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1); +} +MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_int_obj, sensor_get_int); + +STATIC const mp_rom_map_elem_t sensor_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_measure), MP_ROM_PTR(&sensor_measure_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_float), MP_ROM_PTR(&sensor_get_float_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_micros), MP_ROM_PTR(&sensor_get_micros_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_millis), MP_ROM_PTR(&sensor_get_millis_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_int), MP_ROM_PTR(&sensor_get_int_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sensor_locals_dict, sensor_locals_dict_table); + +STATIC const mp_obj_type_t sensor_type = { + { &mp_type_type }, + .name = MP_QSTR_Sensor, + .make_new = sensor_make_new, + .locals_dict = (void*)&sensor_locals_dict, +}; + +STATIC const mp_rom_map_elem_t mp_module_zsensor_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zsensor) }, + { MP_ROM_QSTR(MP_QSTR_Sensor), MP_ROM_PTR(&sensor_type) }, + +#define C(name) { MP_ROM_QSTR(MP_QSTR_ ## name), MP_ROM_INT(SENSOR_CHAN_ ## name) } + C(ACCEL_X), + C(ACCEL_Y), + C(ACCEL_Z), + C(GYRO_X), + C(GYRO_Y), + C(GYRO_Z), + C(MAGN_X), + C(MAGN_Y), + C(MAGN_Z), + C(TEMP), + C(PRESS), + C(PROX), + C(HUMIDITY), + C(LIGHT), + C(ALTITUDE), +#undef C +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_zsensor_globals, mp_module_zsensor_globals_table); + +const mp_obj_module_t mp_module_zsensor = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_zsensor_globals, +}; + +#endif //MICROPY_PY_UHASHLIB diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h index 7ff05f45a8..1ac1c35013 100644 --- a/ports/zephyr/mpconfigport.h +++ b/ports/zephyr/mpconfigport.h @@ -67,9 +67,12 @@ #define MICROPY_PY_UERRNO (1) #define MICROPY_PY_USOCKET (1) #endif +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_UTIME (1) #define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_ZEPHYR (1) +#define MICROPY_PY_ZSENSOR (1) #define MICROPY_PY_SYS_MODULES (0) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) @@ -109,6 +112,7 @@ extern const struct _mp_obj_module_t mp_module_machine; extern const struct _mp_obj_module_t mp_module_time; extern const struct _mp_obj_module_t mp_module_usocket; extern const struct _mp_obj_module_t mp_module_zephyr; +extern const struct _mp_obj_module_t mp_module_zsensor; #if MICROPY_PY_USOCKET #define MICROPY_PY_USOCKET_DEF { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) }, @@ -130,11 +134,18 @@ extern const struct _mp_obj_module_t mp_module_zephyr; #define MICROPY_PY_ZEPHYR_DEF #endif +#if MICROPY_PY_ZSENSOR +#define MICROPY_PY_ZSENSOR_DEF { MP_ROM_QSTR(MP_QSTR_zsensor), MP_ROM_PTR(&mp_module_zsensor) }, +#else +#define MICROPY_PY_ZSENSOR_DEF +#endif + #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ MICROPY_PY_USOCKET_DEF \ MICROPY_PY_UTIME_DEF \ MICROPY_PY_ZEPHYR_DEF \ + MICROPY_PY_ZSENSOR_DEF \ #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time) }, \ diff --git a/ports/zephyr/mpconfigport_bin_testsuite.h b/ports/zephyr/mpconfigport_bin_testsuite.h new file mode 100644 index 0000000000..684b4f41c2 --- /dev/null +++ b/ports/zephyr/mpconfigport_bin_testsuite.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "mpconfigport.h" + +#ifdef TEST +#include "lib/upytesthelper/upytesthelper.h" +#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len) +#endif diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf index fbcedf2600..c39779548f 100644 --- a/ports/zephyr/prj_base.conf +++ b/ports/zephyr/prj_base.conf @@ -1,4 +1,4 @@ -CONFIG_LEGACY_KERNEL=n +CONFIG_BUILD_OUTPUT_BIN=y CONFIG_REBOOT=y CONFIG_STDOUT_CONSOLE=y @@ -12,7 +12,11 @@ CONFIG_CONSOLE_PUTCHAR_BUFSIZE=128 CONFIG_NEWLIB_LIBC=y CONFIG_FLOAT=y -CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_MAIN_STACK_SIZE=4736 + +# Enable sensor subsystem (doesn't add code if not used). +# Specific sensors should be enabled per-board. +CONFIG_SENSOR=y # Networking config CONFIG_NETWORKING=y @@ -28,16 +32,22 @@ CONFIG_NET_APP_SETTINGS=y CONFIG_NET_APP_INIT_TIMEOUT=3 CONFIG_NET_APP_NEED_IPV6=y CONFIG_NET_APP_NEED_IPV4=y -CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" -CONFIG_NET_APP_MY_IPV4_GW="192.0.2.2" # DNS CONFIG_DNS_RESOLVER=y CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2 CONFIG_DNS_SERVER_IP_ADDRESSES=y + +# Static IP addresses +CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_APP_MY_IPV4_GW="192.0.2.2" CONFIG_DNS_SERVER1="192.0.2.2" +# DHCP configuration. Until DHCP address is assigned, +# static configuration above is used instead. +CONFIG_NET_DHCPV4=y + # Diagnostics and debugging # Required for zephyr.stack_analyze() diff --git a/ports/zephyr/prj_disco_l475_iot1.conf b/ports/zephyr/prj_disco_l475_iot1.conf new file mode 100644 index 0000000000..36c8b99ddb --- /dev/null +++ b/ports/zephyr/prj_disco_l475_iot1.conf @@ -0,0 +1,5 @@ +# Sensors +CONFIG_HTS221=y +CONFIG_LIS3MDL=y +CONFIG_LPS22HB=y +CONFIG_LSM6DSL=y diff --git a/py/asmarm.c b/py/asmarm.c index 552fdfb344..1a8923bc23 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -150,10 +150,7 @@ void asm_arm_bkpt(asm_arm_t *as) { // | low address | high address in RAM void asm_arm_entry(asm_arm_t *as, int num_locals) { - - if (num_locals < 0) { - num_locals = 0; - } + assert(num_locals >= 0); as->stack_adjust = 0; as->push_reglist = 1 << ASM_ARM_REG_R1 diff --git a/py/asmarm.h b/py/asmarm.h index 9392a0fae6..fbfe09aacd 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -167,17 +167,12 @@ void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp); } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_arm_bl_ind(as, ptr, idx, ASM_ARM_REG_R3) -#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_arm_mov_local_reg(as, (local_num), (reg)) -#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm)) -#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm)) -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_arm_mov_reg_i32(as, (reg_temp), (imm)); \ - asm_arm_mov_local_reg(as, (local_num), (reg_temp)); \ - } while (false) -#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_arm_mov_reg_local(as, (reg), (local_num)) +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_arm_mov_local_reg((as), (local_num), (reg_src)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_arm_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_arm_mov_reg_reg((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_arm_mov_reg_local_addr(as, (reg), (local_num)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_arm_mov_reg_local_addr((as), (reg_dest), (local_num)) #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_reg_reg((as), (reg_dest), (reg_shift)) #define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_reg_reg((as), (reg_dest), (reg_shift)) diff --git a/py/asmbase.c b/py/asmbase.c index c941e917b7..4c84c3b255 100644 --- a/py/asmbase.c +++ b/py/asmbase.c @@ -46,10 +46,10 @@ void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code) { } void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) { - if (pass == MP_ASM_PASS_COMPUTE) { - // reset all labels + if (pass < MP_ASM_PASS_EMIT) { + // Reset labels so we can detect backwards jumps (and verify unique assignment) memset(as->label_offsets, -1, as->max_num_labels * sizeof(size_t)); - } else if (pass == MP_ASM_PASS_EMIT) { + } else { // allocating executable RAM is platform specific MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); assert(as->code_base != NULL); diff --git a/py/asmthumb.c b/py/asmthumb.c index 5316a7efb2..c5b45f2f51 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -104,6 +104,8 @@ STATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) { // | low address | high address in RAM void asm_thumb_entry(asm_thumb_t *as, int num_locals) { + assert(num_locals >= 0); + // work out what to push and how many extra spaces to reserve on stack // so that we have enough for all locals and it's aligned an 8-byte boundary // we push extra regs (r1, r2, r3) to help do the stack adjustment @@ -111,9 +113,6 @@ void asm_thumb_entry(asm_thumb_t *as, int num_locals) { // for push rlist, lowest numbered register at the lowest address uint reglist; uint stack_adjust; - if (num_locals < 0) { - num_locals = 0; - } // don't pop r0 because it's used for return value switch (num_locals) { case 0: diff --git a/py/asmthumb.h b/py/asmthumb.h index a19c11b2c2..f8665f35cc 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -26,6 +26,7 @@ #ifndef MICROPY_INCLUDED_PY_ASMTHUMB_H #define MICROPY_INCLUDED_PY_ASMTHUMB_H +#include #include "py/misc.h" #include "py/asmbase.h" @@ -283,17 +284,12 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_thumb_bl_ind(as, ptr, idx, ASM_THUMB_REG_R3) -#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_thumb_mov_local_reg(as, (local_num), (reg)) -#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_optimised(as, (reg), (imm)) -#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_aligned(as, (reg), (imm)) -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_thumb_mov_reg_i32_optimised(as, (reg_temp), (imm)); \ - asm_thumb_mov_local_reg(as, (local_num), (reg_temp)); \ - } while (false) -#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local(as, (reg), (local_num)) +#define ASM_MOV_LOCAL_REG(as, local_num, reg) asm_thumb_mov_local_reg((as), (local_num), (reg)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_optimised((as), (reg_dest), (imm)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_aligned((as), (reg_dest), (imm)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_thumb_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local_addr(as, (reg), (local_num)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_thumb_mov_reg_local_addr((as), (reg_dest), (local_num)) #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSL, (reg_dest), (reg_shift)) #define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ASR, (reg_dest), (reg_shift)) diff --git a/py/asmx64.c b/py/asmx64.c index aa2a8ec7cc..c900a08d1f 100644 --- a/py/asmx64.c +++ b/py/asmx64.c @@ -526,11 +526,9 @@ void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) { } void asm_x64_entry(asm_x64_t *as, int num_locals) { + assert(num_locals >= 0); asm_x64_push_r64(as, ASM_X64_REG_RBP); asm_x64_mov_r64_r64(as, ASM_X64_REG_RBP, ASM_X64_REG_RSP); - if (num_locals < 0) { - num_locals = 0; - } num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, num_locals * WORD_SIZE); asm_x64_push_r64(as, ASM_X64_REG_RBX); diff --git a/py/asmx64.h b/py/asmx64.h index bf8bbd1624..9ed2a6cf95 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -162,17 +162,12 @@ void asm_x64_call_ind(asm_x64_t* as, void* ptr, int temp_r32); } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_x64_call_ind(as, ptr, ASM_X64_REG_RAX) -#define ASM_MOV_REG_TO_LOCAL asm_x64_mov_r64_to_local -#define ASM_MOV_IMM_TO_REG asm_x64_mov_i64_to_r64_optimised -#define ASM_MOV_ALIGNED_IMM_TO_REG asm_x64_mov_i64_to_r64_aligned -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_x64_mov_i64_to_r64_optimised(as, (imm), (reg_temp)); \ - asm_x64_mov_r64_to_local(as, (reg_temp), (local_num)); \ - } while (false) -#define ASM_MOV_LOCAL_TO_REG asm_x64_mov_local_to_r64 +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x64_mov_r64_to_local((as), (reg_src), (local_num)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x64_mov_i64_to_r64_optimised((as), (imm), (reg_dest)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_x64_mov_i64_to_r64_aligned((as), (imm), (reg_dest)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x64_mov_local_to_r64((as), (local_num), (reg_dest)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x64_mov_r64_r64((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG asm_x64_mov_local_addr_to_r64 +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x64_mov_local_addr_to_r64((as), (local_num), (reg_dest)) #define ASM_LSL_REG(as, reg) asm_x64_shl_r64_cl((as), (reg)) #define ASM_ASR_REG(as, reg) asm_x64_sar_r64_cl((as), (reg)) diff --git a/py/asmx86.c b/py/asmx86.c index 6a78fbd5ea..3938baaacb 100644 --- a/py/asmx86.c +++ b/py/asmx86.c @@ -387,7 +387,8 @@ void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) { } } -void asm_x86_entry(asm_x86_t *as, mp_uint_t num_locals) { +void asm_x86_entry(asm_x86_t *as, int num_locals) { + assert(num_locals >= 0); asm_x86_push_r32(as, ASM_X86_REG_EBP); asm_x86_mov_r32_r32(as, ASM_X86_REG_EBP, ASM_X86_REG_ESP); if (num_locals > 0) { diff --git a/py/asmx86.h b/py/asmx86.h index a5902987c3..eb6c03eacb 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -104,7 +104,7 @@ void asm_x86_test_r8_with_r8(asm_x86_t* as, int src_r32_a, int src_r32_b); void asm_x86_setcc_r8(asm_x86_t* as, mp_uint_t jcc_type, int dest_r8); void asm_x86_jmp_label(asm_x86_t* as, mp_uint_t label); void asm_x86_jcc_label(asm_x86_t* as, mp_uint_t jcc_type, mp_uint_t label); -void asm_x86_entry(asm_x86_t* as, mp_uint_t num_locals); +void asm_x86_entry(asm_x86_t* as, int num_locals); void asm_x86_exit(asm_x86_t* as); void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32); void asm_x86_mov_local_to_r32(asm_x86_t* as, int src_local_num, int dest_r32); @@ -160,17 +160,12 @@ void asm_x86_call_ind(asm_x86_t* as, void* ptr, mp_uint_t n_args, int temp_r32); } while (0) #define ASM_CALL_IND(as, ptr, idx) asm_x86_call_ind(as, ptr, mp_f_n_args[idx], ASM_X86_REG_EAX) -#define ASM_MOV_REG_TO_LOCAL asm_x86_mov_r32_to_local -#define ASM_MOV_IMM_TO_REG asm_x86_mov_i32_to_r32 -#define ASM_MOV_ALIGNED_IMM_TO_REG asm_x86_mov_i32_to_r32_aligned -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_x86_mov_i32_to_r32(as, (imm), (reg_temp)); \ - asm_x86_mov_r32_to_local(as, (reg_temp), (local_num)); \ - } while (false) -#define ASM_MOV_LOCAL_TO_REG asm_x86_mov_local_to_r32 +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x86_mov_r32_to_local((as), (reg_src), (local_num)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_x86_mov_i32_to_r32_aligned((as), (imm), (reg_dest)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x86_mov_local_to_r32((as), (local_num), (reg_dest)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x86_mov_r32_r32((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG asm_x86_mov_local_addr_to_r32 +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x86_mov_local_addr_to_r32((as), (local_num), (reg_dest)) #define ASM_LSL_REG(as, reg) asm_x86_shl_r32_cl((as), (reg)) #define ASM_ASR_REG(as, reg) asm_x86_sar_r32_cl((as), (reg)) diff --git a/py/asmxtensa.h b/py/asmxtensa.h index 69de24b812..13d3e82346 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -280,17 +280,12 @@ void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_nu asm_xtensa_op_callx0(as, ASM_XTENSA_REG_A0); \ } while (0) -#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_xtensa_mov_local_reg(as, (local_num), (reg)) -#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_xtensa_mov_reg_i32(as, (reg), (imm)) -#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_xtensa_mov_reg_i32(as, (reg), (imm)) -#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \ - do { \ - asm_xtensa_mov_reg_i32(as, (reg_temp), (imm)); \ - asm_xtensa_mov_local_reg(as, (local_num), (reg_temp)); \ - } while (0) -#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_xtensa_mov_reg_local(as, (reg), (local_num)) +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), (local_num), (reg_src)) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm)) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), (local_num)) #define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mov_n((as), (reg_dest), (reg_src)) -#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_xtensa_mov_reg_local_addr(as, (reg), (local_num)) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), (local_num)) #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) \ do { \ diff --git a/py/builtinhelp.c b/py/builtinhelp.c index 1cea8caac2..4cea7e6d57 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -70,7 +70,7 @@ STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) { while (*name) { size_t l = strlen(name); // name should end in '.py' and we strip it off - mp_obj_list_append(list, mp_obj_new_str(name, l - 3, false)); + mp_obj_list_append(list, mp_obj_new_str(name, l - 3)); name += l + 1; } } @@ -109,7 +109,7 @@ STATIC void mp_help_print_modules(void) { // print the list of modules in a column-first order #define NUM_COLUMNS (4) #define COLUMN_WIDTH (18) - mp_uint_t len; + size_t len; mp_obj_t *items; mp_obj_list_get(list, &len, &items); unsigned int num_rows = (len + NUM_COLUMNS - 1) / NUM_COLUMNS; diff --git a/py/builtinimport.c b/py/builtinimport.c index c1437da4c2..649cd11ef2 100755 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -46,6 +46,8 @@ #define DEBUG_printf(...) (void)0 #endif +#if MICROPY_ENABLE_EXTERNAL_IMPORT + #define PATH_SEP_CHAR '/' bool mp_obj_is_package(mp_obj_t module) { @@ -335,7 +337,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); - char *new_mod = alloca(new_mod_l); + char *new_mod = mp_local_alloc(new_mod_l); memcpy(new_mod, this_name, p - this_name); if (mod_len != 0) { new_mod[p - this_name] = '.'; @@ -343,9 +345,10 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l); + mp_local_free(new_mod); DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); module_name = MP_OBJ_NEW_QSTR(new_mod_q); - mod_str = new_mod; + mod_str = qstr_str(new_mod_q); mod_len = new_mod_l; } @@ -406,6 +409,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } // found weak linked module module_obj = el->value; + mp_module_call_init(mod_name, module_obj); } else { no_exist: #else @@ -452,7 +456,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path)); // https://docs.python.org/3/reference/import.html // "Specifically, any module that contains a __path__ attribute is considered a package." - mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false)); + mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path))); size_t orig_path_len = path.len; vstr_add_char(&path, PATH_SEP_CHAR); vstr_add_str(&path, "__init__.py"); @@ -497,4 +501,41 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // Otherwise, we need to return top-level package return top_module_obj; } + +#else // MICROPY_ENABLE_EXTERNAL_IMPORT + +mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { + // Check that it's not a relative import + if (n_args >= 5 && MP_OBJ_SMALL_INT_VALUE(args[4]) != 0) { + mp_raise_NotImplementedError("relative import"); + } + + // Check if module already exists, and return it if it does + qstr module_name_qstr = mp_obj_str_get_qstr(args[0]); + mp_obj_t module_obj = mp_module_get(module_name_qstr); + if (module_obj != MP_OBJ_NULL) { + return module_obj; + } + + #if MICROPY_MODULE_WEAK_LINKS + // Check if there is a weak link to this module + mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(module_name_qstr), MP_MAP_LOOKUP); + if (el != NULL) { + // Found weak-linked module + mp_module_call_init(module_name_qstr, el->value); + return el->value; + } + #endif + + // Couldn't find the module, so fail + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_msg(&mp_type_ImportError, "module not found"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, + "no module named '%q'", module_name_qstr)); + } +} + +#endif // MICROPY_ENABLE_EXTERNAL_IMPORT + MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__); diff --git a/py/compile.c b/py/compile.c index 4e704abfbb..7daf911035 100644 --- a/py/compile.c +++ b/py/compile.c @@ -65,16 +65,16 @@ typedef enum { // we need a method table to do the lookup for the emitter functions #define EMIT(fun) (comp->emit_method_table->fun(comp->emit)) #define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__)) -#define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.fast(comp->emit, qst, local_num)) -#define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst)) +#define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST)) +#define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL)) #else // if we only have the bytecode emitter enabled then we can do a direct call to the functions #define EMIT(fun) (mp_emit_bc_##fun(comp->emit)) #define EMIT_ARG(fun, ...) (mp_emit_bc_##fun(comp->emit, __VA_ARGS__)) -#define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_fast(comp->emit, qst, local_num)) -#define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst)) +#define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST)) +#define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL)) #endif @@ -273,7 +273,7 @@ STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t } total += n; } - EMIT_ARG(build_tuple, total); + EMIT_ARG(build, total, MP_EMIT_BUILD_TUPLE); } STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -366,37 +366,32 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { if (assign_kind == ASSIGN_AUG_STORE) { EMIT(rot_three); - EMIT(store_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE); } else { compile_node(comp, pns1->nodes[0]); if (assign_kind == ASSIGN_AUG_LOAD) { EMIT(dup_top_two); - EMIT(load_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD); } else { - EMIT(store_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE); } } + return; } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); if (assign_kind == ASSIGN_AUG_LOAD) { EMIT(dup_top); - EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_LOAD); } else { if (assign_kind == ASSIGN_AUG_STORE) { EMIT(rot_two); } - EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_STORE); } - } else { - goto cannot_assign; + return; } - } else { - goto cannot_assign; } - return; - -cannot_assign: compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression"); } @@ -657,12 +652,12 @@ STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn) // in MicroPython we put the default positional parameters into a tuple using the bytecode // we need to do this here before we start building the map for the default keywords if (comp->num_default_params > 0) { - EMIT_ARG(build_tuple, comp->num_default_params); + EMIT_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE); } else { EMIT(load_null); // sentinel indicating empty default positional args } // first default dict param, so make the map - EMIT_ARG(build_map, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); } // compile value then key, then store it to the dict @@ -698,7 +693,7 @@ STATIC void compile_funcdef_lambdef(compiler_t *comp, scope_t *scope, mp_parse_n // in MicroPython we put the default positional parameters into a tuple using the bytecode // the default keywords args may have already made the tuple; if not, do it now if (comp->num_default_params > 0 && comp->num_dict_params == 0) { - EMIT_ARG(build_tuple, comp->num_default_params); + EMIT_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE); EMIT(load_null); // sentinel indicating empty default keyword args } @@ -825,7 +820,7 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, name_nodes[0]); for (int j = 1; j < name_len; j++) { assert(MP_PARSE_NODE_IS_ID(name_nodes[j])); // should be - EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j]), MP_EMIT_ATTR_LOAD); } // nodes[1] contains arguments to the decorator function, if any @@ -889,10 +884,10 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { } if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { compile_node(comp, pns1->nodes[0]); - EMIT(delete_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_DELETE); } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); - EMIT_ARG(delete_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_DELETE); } else { goto cannot_delete; } @@ -950,20 +945,21 @@ STATIC void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { apply_to_single_or_list(comp, pns->nodes[0], PN_exprlist, c_del_stmt); } -STATIC void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { - if (comp->break_label == INVALID_LABEL) { - compile_syntax_error(comp, (mp_parse_node_t)pns, "'break' outside loop"); +STATIC void compile_break_cont_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + uint16_t label; + const char *error_msg; + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_break_stmt) { + label = comp->break_label; + error_msg = "'break' outside loop"; + } else { + label = comp->continue_label; + error_msg = "'continue' outside loop"; + } + if (label == INVALID_LABEL) { + compile_syntax_error(comp, (mp_parse_node_t)pns, error_msg); } assert(comp->cur_except_level >= comp->break_continue_except_level); - EMIT_ARG(break_loop, comp->break_label, comp->cur_except_level - comp->break_continue_except_level); -} - -STATIC void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { - if (comp->continue_label == INVALID_LABEL) { - compile_syntax_error(comp, (mp_parse_node_t)pns, "'continue' outside loop"); - } - assert(comp->cur_except_level >= comp->break_continue_except_level); - EMIT_ARG(continue_loop, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level); + EMIT_ARG(unwind_jump, label, comp->cur_except_level - comp->break_continue_except_level); } STATIC void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -1029,14 +1025,14 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { if (MP_PARSE_NODE_IS_NULL(pn)) { // empty name (eg, from . import x) *q_base = MP_QSTR_; - EMIT_ARG(import_name, MP_QSTR_); // import the empty string + EMIT_ARG(import, MP_QSTR_, MP_EMIT_IMPORT_NAME); // import the empty string } else if (MP_PARSE_NODE_IS_ID(pn)) { // just a simple name qstr q_full = MP_PARSE_NODE_LEAF_ARG(pn); if (!is_as) { *q_base = q_full; } - EMIT_ARG(import_name, q_full); + EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME); } else { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_name)); // should be mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; @@ -1050,8 +1046,8 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { for (int i = 0; i < n; i++) { len += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); } - byte *q_ptr; - byte *str_dest = qstr_build_start(len, &q_ptr); + char *q_ptr = mp_local_alloc(len); + char *str_dest = q_ptr; for (int i = 0; i < n; i++) { if (i > 0) { *str_dest++ = '.'; @@ -1061,11 +1057,12 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) { memcpy(str_dest, str_src, str_src_len); str_dest += str_src_len; } - qstr q_full = qstr_build_end(q_ptr); - EMIT_ARG(import_name, q_full); + qstr q_full = qstr_from_strn(q_ptr, len); + mp_local_free(q_ptr); + EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME); if (is_as) { for (int i = 1; i < n; i++) { - EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), MP_EMIT_ATTR_LOAD); } } } @@ -1126,12 +1123,12 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { // build the "fromlist" tuple EMIT_ARG(load_const_str, MP_QSTR__star_); - EMIT_ARG(build_tuple, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_TUPLE); // do the import qstr dummy_q; do_import_name(comp, pn_import_source, &dummy_q); - EMIT(import_star); + EMIT_ARG(import, MP_QSTR_NULL, MP_EMIT_IMPORT_STAR); } else { EMIT_ARG(load_const_small_int, import_level); @@ -1145,7 +1142,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id EMIT_ARG(load_const_str, id2); } - EMIT_ARG(build_tuple, n); + EMIT_ARG(build, n, MP_EMIT_BUILD_TUPLE); // do the import qstr dummy_q; @@ -1154,7 +1151,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name)); mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i]; qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id - EMIT_ARG(import_from, id2); + EMIT_ARG(import, id2, MP_EMIT_IMPORT_FROM); if (MP_PARSE_NODE_IS_NULL(pns3->nodes[1])) { compile_store_id(comp, id2); } else { @@ -1165,9 +1162,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) { } } -STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qst) { - bool added; - id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); +STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qst, bool added, id_info_t *id_info) { if (!added && id_info->kind != ID_INFO_KIND_GLOBAL_EXPLICIT) { compile_syntax_error(comp, pn, "identifier redefined as global"); return; @@ -1181,19 +1176,7 @@ STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qs } } -STATIC void compile_global_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { - if (comp->pass == MP_PASS_SCOPE) { - mp_parse_node_t *nodes; - int n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes); - for (int i = 0; i < n; i++) { - compile_declare_global(comp, (mp_parse_node_t)pns, MP_PARSE_NODE_LEAF_ARG(nodes[i])); - } - } -} - -STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst) { - bool added; - id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); +STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst, bool added, id_info_t *id_info) { if (added) { scope_find_local_and_close_over(comp->scope_cur, id_info, qst); if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { @@ -1204,16 +1187,26 @@ STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr } } -STATIC void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { +STATIC void compile_global_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->pass == MP_PASS_SCOPE) { - if (comp->scope_cur->kind == SCOPE_MODULE) { + bool is_global = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_global_stmt; + + if (!is_global && comp->scope_cur->kind == SCOPE_MODULE) { compile_syntax_error(comp, (mp_parse_node_t)pns, "can't declare nonlocal in outer code"); return; } + mp_parse_node_t *nodes; int n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes); for (int i = 0; i < n; i++) { - compile_declare_nonlocal(comp, (mp_parse_node_t)pns, MP_PARSE_NODE_LEAF_ARG(nodes[i])); + qstr qst = MP_PARSE_NODE_LEAF_ARG(nodes[i]); + bool added; + id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added); + if (is_global) { + compile_declare_global(comp, (mp_parse_node_t)pns, qst, added, id_info); + } else { + compile_declare_nonlocal(comp, (mp_parse_node_t)pns, qst, added, id_info); + } } } } @@ -1520,7 +1513,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ uint l1 = comp_next_label(comp); uint success_label = comp_next_label(comp); - EMIT_ARG(setup_except, l1); + EMIT_ARG(setup_block, l1, MP_EMIT_SETUP_BLOCK_EXCEPT); compile_increase_except_level(comp); compile_node(comp, pn_body); // body @@ -1575,7 +1568,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ uint l3 = 0; if (qstr_exception_local != 0) { l3 = comp_next_label(comp); - EMIT_ARG(setup_finally, l3); + EMIT_ARG(setup_block, l3, MP_EMIT_SETUP_BLOCK_FINALLY); compile_increase_except_level(comp); } compile_node(comp, pns_except->nodes[1]); @@ -1610,7 +1603,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_ STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) { uint l_finally_block = comp_next_label(comp); - EMIT_ARG(setup_finally, l_finally_block); + EMIT_ARG(setup_block, l_finally_block, MP_EMIT_SETUP_BLOCK_FINALLY); compile_increase_except_level(comp); if (n_except == 0) { @@ -1672,12 +1665,12 @@ STATIC void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *n // this pre-bit is of the form "a as b" mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0]; compile_node(comp, pns->nodes[0]); - EMIT_ARG(setup_with, l_end); + EMIT_ARG(setup_block, l_end, MP_EMIT_SETUP_BLOCK_WITH); c_assign(comp, pns->nodes[1], ASSIGN_STORE); } else { // this pre-bit is just an expression compile_node(comp, nodes[0]); - EMIT_ARG(setup_with, l_end); + EMIT_ARG(setup_block, l_end, MP_EMIT_SETUP_BLOCK_WITH); EMIT(pop_top); } compile_increase_except_level(comp); @@ -1703,7 +1696,7 @@ STATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_yield_from(compiler_t *comp) { EMIT_ARG(get_iter, false); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - EMIT(yield_from); + EMIT_ARG(yield, MP_EMIT_YIELD_FROM); } #if MICROPY_PY_ASYNC_AWAIT @@ -1730,7 +1723,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns EMIT_ARG(label_assign, continue_label); - EMIT_ARG(setup_except, try_exception_label); + EMIT_ARG(setup_block, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT); compile_increase_except_level(comp); compile_load_id(comp, context); @@ -1801,7 +1794,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod compile_load_id(comp, context); EMIT_ARG(load_method, MP_QSTR___aexit__, false); - EMIT_ARG(setup_except, try_exception_label); + EMIT_ARG(setup_block, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT); compile_increase_except_level(comp); // compile additional pre-bits and the body compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body); @@ -1815,7 +1808,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod // at this point the stack contains: ..., __aexit__, self, exc EMIT(dup_top); #if MICROPY_CPYTHON_COMPAT - EMIT_ARG(load_attr, MP_QSTR___class__); // get type(exc) + EMIT_ARG(attr, MP_QSTR___class__, MP_EMIT_ATTR_LOAD); // get type(exc) #else compile_load_id(comp, MP_QSTR_type); EMIT(rot_two); @@ -1940,66 +1933,58 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { } } else { plain_assign: - if (MICROPY_COMP_DOUBLE_TUPLE_ASSIGN - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 2 - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 2) { - // optimisation for a, b = c, d - mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1]; + #if MICROPY_COMP_DOUBLE_TUPLE_ASSIGN + if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) + && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)) { mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; - if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) - || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)) { - // can't optimise when it's a star expression on the lhs - goto no_optimisation; + pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + uint32_t n_pns0 = MP_PARSE_NODE_STRUCT_NUM_NODES(pns0); + // Can only optimise a tuple-to-tuple assignment when all of the following hold: + // - equal number of items in LHS and RHS tuples + // - 2 or 3 items in the tuples + // - there are no star expressions in the LHS tuple + if (n_pns0 == MP_PARSE_NODE_STRUCT_NUM_NODES(pns1) + && (n_pns0 == 2 + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + || n_pns0 == 3 + #endif + ) + && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) + && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + && (n_pns0 == 2 || !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) + #endif + ) { + // Optimisation for a, b = c, d or a, b, c = d, e, f + compile_node(comp, pns1->nodes[0]); // rhs + compile_node(comp, pns1->nodes[1]); // rhs + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + if (n_pns0 == 3) { + compile_node(comp, pns1->nodes[2]); // rhs + EMIT(rot_three); + } + #endif + EMIT(rot_two); + c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store + c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + if (n_pns0 == 3) { + c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store + } + #endif + return; } - compile_node(comp, pns10->nodes[0]); // rhs - compile_node(comp, pns10->nodes[1]); // rhs - EMIT(rot_two); - c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store - c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store - } else if (MICROPY_COMP_TRIPLE_TUPLE_ASSIGN - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 3 - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 3) { - // optimisation for a, b, c = d, e, f - mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1]; - mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; - if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) - || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) - || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) { - // can't optimise when it's a star expression on the lhs - goto no_optimisation; - } - compile_node(comp, pns10->nodes[0]); // rhs - compile_node(comp, pns10->nodes[1]); // rhs - compile_node(comp, pns10->nodes[2]); // rhs - EMIT(rot_three); - EMIT(rot_two); - c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store - c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store - c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store - } else { - no_optimisation: - compile_node(comp, pns->nodes[1]); // rhs - c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store } + #endif + + compile_node(comp, pns->nodes[1]); // rhs + c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store } } else { goto plain_assign; } } -STATIC void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) { - int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); - compile_node(comp, pns->nodes[0]); - for (int i = 1; i < num_nodes; i += 1) { - compile_node(comp, pns->nodes[i]); - EMIT_ARG(binary_op, binary_op); - } -} - STATIC void compile_test_if_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_test_if_else)); mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns->nodes[1]; @@ -2030,7 +2015,8 @@ STATIC void compile_lambdef(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_funcdef_lambdef(comp, this_scope, pns->nodes[0], PN_varargslist); } -STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns, bool cond) { +STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { + bool cond = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test; uint l_end = comp_next_label(comp); int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); for (int i = 0; i < n; i += 1) { @@ -2042,14 +2028,6 @@ STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns, b EMIT_ARG(label_assign, l_end); } -STATIC void compile_or_test(compiler_t *comp, mp_parse_node_struct_t *pns) { - compile_or_and_test(comp, pns, true); -} - -STATIC void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { - compile_or_and_test(comp, pns, false); -} - STATIC void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[0]); EMIT_ARG(unary_op, MP_UNARY_OP_NOT); @@ -2115,16 +2093,16 @@ STATIC void compile_star_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_syntax_error(comp, (mp_parse_node_t)pns, "*x must be assignment target"); } -STATIC void compile_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { - c_binary_op(comp, pns, MP_BINARY_OP_OR); -} - -STATIC void compile_xor_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { - c_binary_op(comp, pns, MP_BINARY_OP_XOR); -} - -STATIC void compile_and_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { - c_binary_op(comp, pns, MP_BINARY_OP_AND); +STATIC void compile_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns) { + MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_xor_expr - PN_expr == MP_BINARY_OP_XOR); + MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_and_expr - PN_expr == MP_BINARY_OP_AND); + mp_binary_op_t binary_op = MP_BINARY_OP_OR + MP_PARSE_NODE_STRUCT_KIND(pns) - PN_expr; + int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); + compile_node(comp, pns->nodes[0]); + for (int i = 1; i < num_nodes; ++i) { + compile_node(comp, pns->nodes[i]); + EMIT_ARG(binary_op, binary_op); + } } STATIC void compile_term(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -2400,7 +2378,7 @@ STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) { if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // empty list - EMIT_ARG(build_list, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[0]; if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) { @@ -2409,12 +2387,12 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) // list of one item, with trailing comma assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0])); compile_node(comp, pns2->nodes[0]); - EMIT_ARG(build_list, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST); } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) { // list of many items compile_node(comp, pns2->nodes[0]); compile_generic_all_nodes(comp, pns3); - EMIT_ARG(build_list, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3)); + EMIT_ARG(build, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3), MP_EMIT_BUILD_LIST); } else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) { // list comprehension compile_comprehension(comp, pns2, SCOPE_LIST_COMP); @@ -2427,12 +2405,12 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) list_with_2_items: compile_node(comp, pns2->nodes[0]); compile_node(comp, pns2->nodes[1]); - EMIT_ARG(build_list, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_LIST); } } else { // list with 1 item compile_node(comp, pns->nodes[0]); - EMIT_ARG(build_list, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST); } } @@ -2440,12 +2418,12 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { mp_parse_node_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // empty dict - EMIT_ARG(build_map, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker_item) { // dict with one element - EMIT_ARG(build_map, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP); compile_node(comp, pn); EMIT(store_map); } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) { @@ -2462,7 +2440,7 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { bool is_dict; if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) { // a dictionary - EMIT_ARG(build_map, 1 + n); + EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP); compile_node(comp, pns->nodes[0]); EMIT(store_map); is_dict = true; @@ -2502,7 +2480,7 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { #if MICROPY_PY_BUILTINS_SET // if it's a set, build it if (!is_dict) { - EMIT_ARG(build_set, 1 + n); + EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_SET); } #endif } else { @@ -2525,7 +2503,7 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { set_with_one_element: #if MICROPY_PY_BUILTINS_SET compile_node(comp, pn); - EMIT_ARG(build_set, 1); + EMIT_ARG(build, 1, MP_EMIT_BUILD_SET); #else assert(0); #endif @@ -2539,22 +2517,31 @@ STATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns) STATIC void compile_trailer_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) { // object who's index we want is on top of stack compile_node(comp, pns->nodes[0]); // the index - EMIT(load_subscr); + EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD); } STATIC void compile_trailer_period(compiler_t *comp, mp_parse_node_struct_t *pns) { // object who's attribute we want is on top of stack - EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // attribute to get + EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]), MP_EMIT_ATTR_LOAD); // attribute to get } #if MICROPY_PY_BUILTINS_SLICE -STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t *pns) { +STATIC void compile_subscript(compiler_t *comp, mp_parse_node_struct_t *pns) { + if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_2) { + compile_node(comp, pns->nodes[0]); // start of slice + assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be + pns = (mp_parse_node_struct_t*)pns->nodes[1]; + } else { + // pns is a PN_subscript_3, load None for start of slice + EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); + } + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3); // should always be mp_parse_node_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // [?:] EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } else if (MP_PARSE_NODE_IS_STRUCT(pn)) { pns = (mp_parse_node_struct_t*)pn; if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3c) { @@ -2562,11 +2549,11 @@ STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t pn = pns->nodes[0]; if (MP_PARSE_NODE_IS_NULL(pn)) { // [?::] - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } else { // [?::x] compile_node(comp, pn); - EMIT_ARG(build_slice, 3); + EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE); } } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3d) { compile_node(comp, pns->nodes[0]); @@ -2575,34 +2562,23 @@ STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_sliceop); // should always be if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // [?:x:] - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } else { // [?:x:x] compile_node(comp, pns->nodes[0]); - EMIT_ARG(build_slice, 3); + EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE); } } else { // [?:x] compile_node(comp, pn); - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } } else { // [?:x] compile_node(comp, pn); - EMIT_ARG(build_slice, 2); + EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE); } } - -STATIC void compile_subscript_2(compiler_t *comp, mp_parse_node_struct_t *pns) { - compile_node(comp, pns->nodes[0]); // start of slice - assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be - compile_subscript_3_helper(comp, (mp_parse_node_struct_t*)pns->nodes[1]); -} - -STATIC void compile_subscript_3(compiler_t *comp, mp_parse_node_struct_t *pns) { - EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - compile_subscript_3_helper(comp, pns); -} #endif // MICROPY_PY_BUILTINS_SLICE STATIC void compile_dictorsetmaker_item(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -2624,14 +2600,14 @@ STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); - EMIT(yield_value); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) { pns = (mp_parse_node_struct_t*)pns->nodes[0]; compile_node(comp, pns->nodes[0]); compile_yield_from(comp); } else { compile_node(comp, pns->nodes[0]); - EMIT(yield_value); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); } } @@ -2865,7 +2841,7 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_struct_t *pn // no more nested if/for; compile inner expression compile_node(comp, pn_inner_expr); if (comp->scope_cur->kind == SCOPE_GEN_EXPR) { - EMIT(yield_value); + EMIT_ARG(yield, MP_EMIT_YIELD_VALUE); EMIT(pop_top); } else { EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5); @@ -3043,19 +3019,19 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) { } if (scope->kind == SCOPE_LIST_COMP) { - EMIT_ARG(build_list, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST); } else if (scope->kind == SCOPE_DICT_COMP) { - EMIT_ARG(build_map, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP); #if MICROPY_PY_BUILTINS_SET } else if (scope->kind == SCOPE_SET_COMP) { - EMIT_ARG(build_set, 0); + EMIT_ARG(build, 0, MP_EMIT_BUILD_SET); #endif } // There are 4 slots on the stack for the iterator, and the first one is // NULL to indicate that the second one points to the iterator object. if (scope->kind == SCOPE_GEN_EXPR) { - // TODO static assert that MP_OBJ_ITER_BUF_NSLOTS == 4 + MP_STATIC_ASSERT(MP_OBJ_ITER_BUF_NSLOTS == 4); EMIT(load_null); compile_load_id(comp, qstr_arg); EMIT(load_null); diff --git a/py/emit.h b/py/emit.h index 270a40633c..aa98efa774 100644 --- a/py/emit.h +++ b/py/emit.h @@ -55,13 +55,50 @@ typedef enum { #define MP_EMIT_NATIVE_TYPE_RETURN (1) #define MP_EMIT_NATIVE_TYPE_ARG (2) +// Kind for emit_id_ops->local() +#define MP_EMIT_IDOP_LOCAL_FAST (0) +#define MP_EMIT_IDOP_LOCAL_DEREF (1) + +// Kind for emit_id_ops->global() +#define MP_EMIT_IDOP_GLOBAL_NAME (0) +#define MP_EMIT_IDOP_GLOBAL_GLOBAL (1) + +// Kind for emit->import() +#define MP_EMIT_IMPORT_NAME (0) +#define MP_EMIT_IMPORT_FROM (1) +#define MP_EMIT_IMPORT_STAR (2) + +// Kind for emit->subscr() +#define MP_EMIT_SUBSCR_LOAD (0) +#define MP_EMIT_SUBSCR_STORE (1) +#define MP_EMIT_SUBSCR_DELETE (2) + +// Kind for emit->attr() +#define MP_EMIT_ATTR_LOAD (0) +#define MP_EMIT_ATTR_STORE (1) +#define MP_EMIT_ATTR_DELETE (2) + +// Kind for emit->setup_block() +#define MP_EMIT_SETUP_BLOCK_WITH (0) +#define MP_EMIT_SETUP_BLOCK_EXCEPT (2) +#define MP_EMIT_SETUP_BLOCK_FINALLY (3) + +// Kind for emit->build() +#define MP_EMIT_BUILD_TUPLE (0) +#define MP_EMIT_BUILD_LIST (1) +#define MP_EMIT_BUILD_MAP (3) +#define MP_EMIT_BUILD_SET (6) +#define MP_EMIT_BUILD_SLICE (8) + +// Kind for emit->yield() +#define MP_EMIT_YIELD_VALUE (0) +#define MP_EMIT_YIELD_FROM (1) + typedef struct _emit_t emit_t; typedef struct _mp_emit_method_table_id_ops_t { - void (*fast)(emit_t *emit, qstr qst, mp_uint_t local_num); - void (*deref)(emit_t *emit, qstr qst, mp_uint_t local_num); - void (*name)(emit_t *emit, qstr qst); - void (*global)(emit_t *emit, qstr qst); + void (*local)(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); + void (*global)(emit_t *emit, qstr qst, int kind); } mp_emit_method_table_id_ops_t; typedef struct _emit_method_table_t { @@ -77,22 +114,16 @@ typedef struct _emit_method_table_t { mp_emit_method_table_id_ops_t delete_id; void (*label_assign)(emit_t *emit, mp_uint_t l); - void (*import_name)(emit_t *emit, qstr qst); - void (*import_from)(emit_t *emit, qstr qst); - void (*import_star)(emit_t *emit); + void (*import)(emit_t *emit, qstr qst, int kind); void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok); void (*load_const_small_int)(emit_t *emit, mp_int_t arg); void (*load_const_str)(emit_t *emit, qstr qst); void (*load_const_obj)(emit_t *emit, mp_obj_t obj); void (*load_null)(emit_t *emit); - void (*load_attr)(emit_t *emit, qstr qst); void (*load_method)(emit_t *emit, qstr qst, bool is_super); void (*load_build_class)(emit_t *emit); - void (*load_subscr)(emit_t *emit); - void (*store_attr)(emit_t *emit, qstr qst); - void (*store_subscr)(emit_t *emit); - void (*delete_attr)(emit_t *emit, qstr qst); - void (*delete_subscr)(emit_t *emit); + void (*subscr)(emit_t *emit, int kind); + void (*attr)(emit_t *emit, qstr qst, int kind); void (*dup_top)(emit_t *emit); void (*dup_top_two)(emit_t *emit); void (*pop_top)(emit_t *emit); @@ -101,12 +132,9 @@ typedef struct _emit_method_table_t { void (*jump)(emit_t *emit, mp_uint_t label); void (*pop_jump_if)(emit_t *emit, bool cond, mp_uint_t label); void (*jump_if_or_pop)(emit_t *emit, bool cond, mp_uint_t label); - void (*break_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); - void (*continue_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); - void (*setup_with)(emit_t *emit, mp_uint_t label); + void (*unwind_jump)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); + void (*setup_block)(emit_t *emit, mp_uint_t label, int kind); void (*with_cleanup)(emit_t *emit, mp_uint_t label); - void (*setup_except)(emit_t *emit, mp_uint_t label); - void (*setup_finally)(emit_t *emit, mp_uint_t label); void (*end_finally)(emit_t *emit); void (*get_iter)(emit_t *emit, bool use_stack); void (*for_iter)(emit_t *emit, mp_uint_t label); @@ -115,16 +143,8 @@ typedef struct _emit_method_table_t { void (*pop_except)(emit_t *emit); void (*unary_op)(emit_t *emit, mp_unary_op_t op); void (*binary_op)(emit_t *emit, mp_binary_op_t op); - void (*build_tuple)(emit_t *emit, mp_uint_t n_args); - void (*build_list)(emit_t *emit, mp_uint_t n_args); - void (*build_map)(emit_t *emit, mp_uint_t n_args); + void (*build)(emit_t *emit, mp_uint_t n_args, int kind); void (*store_map)(emit_t *emit); - #if MICROPY_PY_BUILTINS_SET - void (*build_set)(emit_t *emit, mp_uint_t n_args); - #endif - #if MICROPY_PY_BUILTINS_SLICE - void (*build_slice)(emit_t *emit, mp_uint_t n_args); - #endif void (*store_comp)(emit_t *emit, scope_kind_t kind, mp_uint_t set_stack_index); void (*unpack_sequence)(emit_t *emit, mp_uint_t n_args); void (*unpack_ex)(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); @@ -134,8 +154,7 @@ typedef struct _emit_method_table_t { void (*call_method)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void (*return_value)(emit_t *emit); void (*raise_varargs)(emit_t *emit, mp_uint_t n_args); - void (*yield_value)(emit_t *emit); - void (*yield_from)(emit_t *emit); + void (*yield)(emit_t *emit, int kind); // these methods are used to control entry to/exit from an exception handler // they may or may not emit code @@ -180,36 +199,24 @@ bool mp_emit_bc_last_emit_was_return_value(emit_t *emit); void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta); void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t line); -void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num); -void mp_emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num); -void mp_emit_bc_load_name(emit_t *emit, qstr qst); -void mp_emit_bc_load_global(emit_t *emit, qstr qst); -void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num); -void mp_emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num); -void mp_emit_bc_store_name(emit_t *emit, qstr qst); -void mp_emit_bc_store_global(emit_t *emit, qstr qst); -void mp_emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num); -void mp_emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num); -void mp_emit_bc_delete_name(emit_t *emit, qstr qst); -void mp_emit_bc_delete_global(emit_t *emit, qstr qst); +void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); +void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind); +void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); +void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind); +void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind); +void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind); void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l); -void mp_emit_bc_import_name(emit_t *emit, qstr qst); -void mp_emit_bc_import_from(emit_t *emit, qstr qst); -void mp_emit_bc_import_star(emit_t *emit); +void mp_emit_bc_import(emit_t *emit, qstr qst, int kind); void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok); void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg); void mp_emit_bc_load_const_str(emit_t *emit, qstr qst); void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj); void mp_emit_bc_load_null(emit_t *emit); -void mp_emit_bc_load_attr(emit_t *emit, qstr qst); void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super); void mp_emit_bc_load_build_class(emit_t *emit); -void mp_emit_bc_load_subscr(emit_t *emit); -void mp_emit_bc_store_attr(emit_t *emit, qstr qst); -void mp_emit_bc_store_subscr(emit_t *emit); -void mp_emit_bc_delete_attr(emit_t *emit, qstr qst); -void mp_emit_bc_delete_subscr(emit_t *emit); +void mp_emit_bc_subscr(emit_t *emit, int kind); +void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind); void mp_emit_bc_dup_top(emit_t *emit); void mp_emit_bc_dup_top_two(emit_t *emit); void mp_emit_bc_pop_top(emit_t *emit); @@ -219,12 +226,8 @@ void mp_emit_bc_jump(emit_t *emit, mp_uint_t label); void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label); void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label); void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); -#define mp_emit_bc_break_loop mp_emit_bc_unwind_jump -#define mp_emit_bc_continue_loop mp_emit_bc_unwind_jump -void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label); +void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind); void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label); -void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label); -void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label); void mp_emit_bc_end_finally(emit_t *emit); void mp_emit_bc_get_iter(emit_t *emit, bool use_stack); void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label); @@ -233,16 +236,8 @@ void mp_emit_bc_pop_block(emit_t *emit); void mp_emit_bc_pop_except(emit_t *emit); void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op); void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op); -void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args); -void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args); -void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args); +void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind); void mp_emit_bc_store_map(emit_t *emit); -#if MICROPY_PY_BUILTINS_SET -void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args); -#endif -#if MICROPY_PY_BUILTINS_SLICE -void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args); -#endif void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t list_stack_index); void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args); void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right); @@ -252,8 +247,7 @@ void mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_ void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags); void mp_emit_bc_return_value(emit_t *emit); void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args); -void mp_emit_bc_yield_value(emit_t *emit); -void mp_emit_bc_yield_from(emit_t *emit); +void mp_emit_bc_yield(emit_t *emit, int kind); void mp_emit_bc_start_except_handler(emit_t *emit); void mp_emit_bc_end_except_handler(emit_t *emit); diff --git a/py/emitbc.c b/py/emitbc.c index 3f4dfc1786..f3951e9cb5 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -313,9 +313,12 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { emit->scope = scope; emit->last_source_line_offset = 0; emit->last_source_line = 1; - if (pass < MP_PASS_EMIT) { + #ifndef NDEBUG + // With debugging enabled labels are checked for unique assignment + if (pass < MP_PASS_EMIT && emit->label_offsets != NULL) { memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t)); } + #endif emit->bytecode_offset = 0; emit->code_info_offset = 0; @@ -434,7 +437,9 @@ void mp_emit_bc_end_pass(emit_t *emit) { } else if (emit->pass == MP_PASS_EMIT) { mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS emit->code_info_size + emit->bytecode_size, + #endif emit->const_table, #if MICROPY_PERSISTENT_CODE_SAVE emit->ct_cur_obj, emit->ct_cur_raw_code, @@ -495,24 +500,23 @@ void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) { emit->label_offsets[l] = emit->bytecode_offset; } else { // ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT - //printf("l%d: (at %d vs %d)\n", l, emit->bytecode_offset, emit->label_offsets[l]); assert(emit->label_offsets[l] == emit->bytecode_offset); } } -void mp_emit_bc_import_name(emit_t *emit, qstr qst) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME, qst); -} - -void mp_emit_bc_import_from(emit_t *emit, qstr qst) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_FROM, qst); -} - -void mp_emit_bc_import_star(emit_t *emit) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR); +void mp_emit_bc_import(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_NAME == MP_BC_IMPORT_NAME); + MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_FROM == MP_BC_IMPORT_FROM); + if (kind == MP_EMIT_IMPORT_FROM) { + emit_bc_pre(emit, 1); + } else { + emit_bc_pre(emit, -1); + } + if (kind == MP_EMIT_IMPORT_STAR) { + emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR); + } else { + emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME + kind, qst); + } } void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) { @@ -552,43 +556,24 @@ void mp_emit_bc_load_null(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL); } -void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { +void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_LOAD_FAST_N); + MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_LOAD_DEREF); (void)qst; emit_bc_pre(emit, 1); - if (local_num <= 15) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num); } else { - emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); + emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N + kind, local_num); } } -void mp_emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { +void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_LOAD_NAME); + MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL); (void)qst; emit_bc_pre(emit, 1); - emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_DEREF, local_num); -} - -void mp_emit_bc_load_name(emit_t *emit, qstr qst) { - (void)qst; - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qst); - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_byte(emit, 0); - } -} - -void mp_emit_bc_load_global(emit_t *emit, qstr qst) { - (void)qst; - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qst); - if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { - emit_write_bytecode_byte(emit, 0); - } -} - -void mp_emit_bc_load_attr(emit_t *emit, qstr qst) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst); + emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME + kind, qst); if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { emit_write_bytecode_byte(emit, 0); } @@ -604,80 +589,68 @@ void mp_emit_bc_load_build_class(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_LOAD_BUILD_CLASS); } -void mp_emit_bc_load_subscr(emit_t *emit) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR); -} - -void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { - (void)qst; - emit_bc_pre(emit, -1); - if (local_num <= 15) { - emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num); +void mp_emit_bc_subscr(emit_t *emit, int kind) { + if (kind == MP_EMIT_SUBSCR_LOAD) { + emit_bc_pre(emit, -1); + emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR); } else { - emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num); + if (kind == MP_EMIT_SUBSCR_DELETE) { + mp_emit_bc_load_null(emit); + mp_emit_bc_rot_three(emit); + } + emit_bc_pre(emit, -3); + emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR); } } -void mp_emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { - (void)qst; - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_uint(emit, MP_BC_STORE_DEREF, local_num); -} - -void mp_emit_bc_store_name(emit_t *emit, qstr qst) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME, qst); -} - -void mp_emit_bc_store_global(emit_t *emit, qstr qst) { - emit_bc_pre(emit, -1); - emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_GLOBAL, qst); -} - -void mp_emit_bc_store_attr(emit_t *emit, qstr qst) { - emit_bc_pre(emit, -2); - emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst); +void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) { + if (kind == MP_EMIT_ATTR_LOAD) { + emit_bc_pre(emit, 0); + emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst); + } else { + if (kind == MP_EMIT_ATTR_DELETE) { + mp_emit_bc_load_null(emit); + mp_emit_bc_rot_two(emit); + } + emit_bc_pre(emit, -2); + emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst); + } if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) { emit_write_bytecode_byte(emit, 0); } } -void mp_emit_bc_store_subscr(emit_t *emit) { - emit_bc_pre(emit, -3); - emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR); -} - -void mp_emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { +void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_STORE_FAST_N); + MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_STORE_DEREF); (void)qst; - emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST, local_num); + emit_bc_pre(emit, -1); + if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) { + emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num); + } else { + emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N + kind, local_num); + } } -void mp_emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { +void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_STORE_NAME); + MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_STORE_GLOBAL); + emit_bc_pre(emit, -1); + emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME + kind, qst); +} + +void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_DELETE_FAST); + MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_DELETE_DEREF); (void)qst; - emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_DEREF, local_num); + emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST + kind, local_num); } -void mp_emit_bc_delete_name(emit_t *emit, qstr qst) { +void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_DELETE_NAME); + MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_DELETE_GLOBAL); emit_bc_pre(emit, 0); - emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME, qst); -} - -void mp_emit_bc_delete_global(emit_t *emit, qstr qst) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_GLOBAL, qst); -} - -void mp_emit_bc_delete_attr(emit_t *emit, qstr qst) { - mp_emit_bc_load_null(emit); - mp_emit_bc_rot_two(emit); - mp_emit_bc_store_attr(emit, qst); -} - -void mp_emit_bc_delete_subscr(emit_t *emit) { - mp_emit_bc_load_null(emit); - mp_emit_bc_rot_three(emit); - mp_emit_bc_store_subscr(emit); + emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME + kind, qst); } void mp_emit_bc_dup_top(emit_t *emit) { @@ -746,11 +719,18 @@ void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_dept } } -void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label) { +void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) { + MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_WITH == MP_BC_SETUP_WITH); + MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_EXCEPT == MP_BC_SETUP_EXCEPT); + MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_FINALLY == MP_BC_SETUP_FINALLY); + if (kind == MP_EMIT_SETUP_BLOCK_WITH) { // The SETUP_WITH opcode pops ctx_mgr from the top of the stack // and then pushes 3 entries: __exit__, ctx_mgr, as_value. - emit_bc_pre(emit, 2); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label); + emit_bc_pre(emit, 2); + } else { + emit_bc_pre(emit, 0); + } + emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH + kind, label); } void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { @@ -759,17 +739,7 @@ void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { mp_emit_bc_label_assign(emit, label); emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP); - emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_with -} - -void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label); -} - -void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label) { - emit_bc_pre(emit, 0); - emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label); + emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH) } void mp_emit_bc_end_finally(emit_t *emit) { @@ -823,19 +793,18 @@ void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) { } } -void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1 - n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE, n_args); -} - -void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1 - n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_LIST, n_args); -} - -void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_MAP, n_args); +void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind) { + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_BC_BUILD_TUPLE); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_BC_BUILD_LIST); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_BC_BUILD_MAP); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_BC_BUILD_SET); + MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SLICE == MP_BC_BUILD_SLICE); + if (kind == MP_EMIT_BUILD_MAP) { + emit_bc_pre(emit, 1); + } else { + emit_bc_pre(emit, 1 - n_args); + } + emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE + kind, n_args); } void mp_emit_bc_store_map(emit_t *emit) { @@ -843,20 +812,6 @@ void mp_emit_bc_store_map(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_STORE_MAP); } -#if MICROPY_PY_BUILTINS_SET -void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1 - n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SET, n_args); -} -#endif - -#if MICROPY_PY_BUILTINS_SLICE -void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args) { - emit_bc_pre(emit, 1 - n_args); - emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SLICE, n_args); -} -#endif - void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) { int t; int n; @@ -938,16 +893,11 @@ void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args); } -void mp_emit_bc_yield_value(emit_t *emit) { - emit_bc_pre(emit, 0); +void mp_emit_bc_yield(emit_t *emit, int kind) { + MP_STATIC_ASSERT(MP_BC_YIELD_VALUE + 1 == MP_BC_YIELD_FROM); + emit_bc_pre(emit, -kind); emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; - emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE); -} - -void mp_emit_bc_yield_from(emit_t *emit) { - emit_bc_pre(emit, -1); - emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; - emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM); + emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE + kind); } void mp_emit_bc_start_except_handler(emit_t *emit) { @@ -968,41 +918,29 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_set_source_line, { - mp_emit_bc_load_fast, - mp_emit_bc_load_deref, - mp_emit_bc_load_name, + mp_emit_bc_load_local, mp_emit_bc_load_global, }, { - mp_emit_bc_store_fast, - mp_emit_bc_store_deref, - mp_emit_bc_store_name, + mp_emit_bc_store_local, mp_emit_bc_store_global, }, { - mp_emit_bc_delete_fast, - mp_emit_bc_delete_deref, - mp_emit_bc_delete_name, + mp_emit_bc_delete_local, mp_emit_bc_delete_global, }, mp_emit_bc_label_assign, - mp_emit_bc_import_name, - mp_emit_bc_import_from, - mp_emit_bc_import_star, + mp_emit_bc_import, mp_emit_bc_load_const_tok, mp_emit_bc_load_const_small_int, mp_emit_bc_load_const_str, mp_emit_bc_load_const_obj, mp_emit_bc_load_null, - mp_emit_bc_load_attr, mp_emit_bc_load_method, mp_emit_bc_load_build_class, - mp_emit_bc_load_subscr, - mp_emit_bc_store_attr, - mp_emit_bc_store_subscr, - mp_emit_bc_delete_attr, - mp_emit_bc_delete_subscr, + mp_emit_bc_subscr, + mp_emit_bc_attr, mp_emit_bc_dup_top, mp_emit_bc_dup_top_two, mp_emit_bc_pop_top, @@ -1012,11 +950,8 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_pop_jump_if, mp_emit_bc_jump_if_or_pop, mp_emit_bc_unwind_jump, - mp_emit_bc_unwind_jump, - mp_emit_bc_setup_with, + mp_emit_bc_setup_block, mp_emit_bc_with_cleanup, - mp_emit_bc_setup_except, - mp_emit_bc_setup_finally, mp_emit_bc_end_finally, mp_emit_bc_get_iter, mp_emit_bc_for_iter, @@ -1025,16 +960,8 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_pop_except, mp_emit_bc_unary_op, mp_emit_bc_binary_op, - mp_emit_bc_build_tuple, - mp_emit_bc_build_list, - mp_emit_bc_build_map, + mp_emit_bc_build, mp_emit_bc_store_map, - #if MICROPY_PY_BUILTINS_SET - mp_emit_bc_build_set, - #endif - #if MICROPY_PY_BUILTINS_SLICE - mp_emit_bc_build_slice, - #endif mp_emit_bc_store_comp, mp_emit_bc_unpack_sequence, mp_emit_bc_unpack_ex, @@ -1044,31 +971,24 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_call_method, mp_emit_bc_return_value, mp_emit_bc_raise_varargs, - mp_emit_bc_yield_value, - mp_emit_bc_yield_from, + mp_emit_bc_yield, mp_emit_bc_start_except_handler, mp_emit_bc_end_except_handler, }; #else const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops = { - mp_emit_bc_load_fast, - mp_emit_bc_load_deref, - mp_emit_bc_load_name, + mp_emit_bc_load_local, mp_emit_bc_load_global, }; const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops = { - mp_emit_bc_store_fast, - mp_emit_bc_store_deref, - mp_emit_bc_store_name, + mp_emit_bc_store_local, mp_emit_bc_store_global, }; const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = { - mp_emit_bc_delete_fast, - mp_emit_bc_delete_deref, - mp_emit_bc_delete_name, + mp_emit_bc_delete_local, mp_emit_bc_delete_global, }; #endif diff --git a/py/emitcommon.c b/py/emitcommon.c index 07b1dbb4ce..89cc2c9597 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -63,14 +63,14 @@ void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emi // call the emit backend with the correct code if (id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) { - emit_method_table->name(emit, qst); + emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_NAME); } else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) { - emit_method_table->global(emit, qst); + emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL); } else if (id->kind == ID_INFO_KIND_LOCAL) { - emit_method_table->fast(emit, qst, id->local_num); + emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_FAST); } else { assert(id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE); - emit_method_table->deref(emit, qst, id->local_num); + emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_DEREF); } } diff --git a/py/emitglue.c b/py/emitglue.c index d2add988f2..74bf8ddca2 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -55,7 +55,10 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) { return rc; } -void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t len, +void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + size_t len, + #endif const mp_uint_t *const_table, #if MICROPY_PERSISTENT_CODE_SAVE uint16_t n_obj, uint16_t n_raw_code, diff --git a/py/emitglue.h b/py/emitglue.h index 43930333d6..0830a0d5c8 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -40,7 +40,7 @@ typedef enum { } mp_raw_code_kind_t; typedef struct _mp_raw_code_t { - mp_raw_code_kind_t kind : 3; + mp_uint_t kind : 3; // of type mp_raw_code_kind_t mp_uint_t scope_flags : 7; mp_uint_t n_pos_args : 11; union { @@ -63,7 +63,10 @@ typedef struct _mp_raw_code_t { mp_raw_code_t *mp_emit_glue_new_raw_code(void); -void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t len, +void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + size_t len, + #endif const mp_uint_t *const_table, #if MICROPY_PERSISTENT_CODE_SAVE uint16_t n_obj, uint16_t n_raw_code, diff --git a/py/emitnarm.c b/py/emitnarm.c new file mode 100644 index 0000000000..1b585f821b --- /dev/null +++ b/py/emitnarm.c @@ -0,0 +1,15 @@ +// ARM specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_ARM + +// This is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmarm.h" + +#define N_ARM (1) +#define EXPORT_FUN(name) emit_native_arm_##name +#include "py/emitnative.c" + +#endif diff --git a/py/emitnative.c b/py/emitnative.c index 8e97dda119..ad8f04aac7 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -57,102 +57,14 @@ #endif // wrapper around everything in this file -#if (MICROPY_EMIT_X64 && N_X64) \ - || (MICROPY_EMIT_X86 && N_X86) \ - || (MICROPY_EMIT_THUMB && N_THUMB) \ - || (MICROPY_EMIT_ARM && N_ARM) \ - || (MICROPY_EMIT_XTENSA && N_XTENSA) \ +#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA -// this is defined so that the assembler exports generic assembler API macros -#define GENERIC_ASM_API (1) - -#if N_X64 - -// x64 specific stuff -#include "py/asmx64.h" -#define EXPORT_FUN(name) emit_native_x64_##name - -#elif N_X86 - -// x86 specific stuff - -STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { - [MP_F_CONVERT_OBJ_TO_NATIVE] = 2, - [MP_F_CONVERT_NATIVE_TO_OBJ] = 2, - [MP_F_LOAD_NAME] = 1, - [MP_F_LOAD_GLOBAL] = 1, - [MP_F_LOAD_BUILD_CLASS] = 0, - [MP_F_LOAD_ATTR] = 2, - [MP_F_LOAD_METHOD] = 3, - [MP_F_LOAD_SUPER_METHOD] = 2, - [MP_F_STORE_NAME] = 2, - [MP_F_STORE_GLOBAL] = 2, - [MP_F_STORE_ATTR] = 3, - [MP_F_OBJ_SUBSCR] = 3, - [MP_F_OBJ_IS_TRUE] = 1, - [MP_F_UNARY_OP] = 2, - [MP_F_BINARY_OP] = 3, - [MP_F_BUILD_TUPLE] = 2, - [MP_F_BUILD_LIST] = 2, - [MP_F_LIST_APPEND] = 2, - [MP_F_BUILD_MAP] = 1, - [MP_F_STORE_MAP] = 3, -#if MICROPY_PY_BUILTINS_SET - [MP_F_BUILD_SET] = 2, - [MP_F_STORE_SET] = 2, -#endif - [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3, - [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3, - [MP_F_CALL_METHOD_N_KW] = 3, - [MP_F_CALL_METHOD_N_KW_VAR] = 3, - [MP_F_NATIVE_GETITER] = 2, - [MP_F_NATIVE_ITERNEXT] = 1, - [MP_F_NLR_PUSH] = 1, - [MP_F_NLR_POP] = 0, - [MP_F_NATIVE_RAISE] = 1, - [MP_F_IMPORT_NAME] = 3, - [MP_F_IMPORT_FROM] = 2, - [MP_F_IMPORT_ALL] = 1, -#if MICROPY_PY_BUILTINS_SLICE - [MP_F_NEW_SLICE] = 3, -#endif - [MP_F_UNPACK_SEQUENCE] = 3, - [MP_F_UNPACK_EX] = 3, - [MP_F_DELETE_NAME] = 1, - [MP_F_DELETE_GLOBAL] = 1, - [MP_F_NEW_CELL] = 1, - [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3, - [MP_F_SETUP_CODE_STATE] = 5, - [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2, - [MP_F_SMALL_INT_MODULO] = 2, -}; - -#include "py/asmx86.h" -#define EXPORT_FUN(name) emit_native_x86_##name - -#elif N_THUMB - -// thumb specific stuff -#include "py/asmthumb.h" -#define EXPORT_FUN(name) emit_native_thumb_##name - -#elif N_ARM - -// ARM specific stuff -#include "py/asmarm.h" -#define EXPORT_FUN(name) emit_native_arm_##name - -#elif N_XTENSA - -// Xtensa specific stuff -#include "py/asmxtensa.h" -#define EXPORT_FUN(name) emit_native_xtensa_##name - -#else - -#error unknown native emitter - -#endif +// define additional generic helper macros +#define ASM_MOV_LOCAL_IMM_VIA(as, local_num, imm, reg_temp) \ + do { \ + ASM_MOV_REG_IMM((as), (reg_temp), (imm)); \ + ASM_MOV_LOCAL_REG((as), (local_num), (reg_temp)); \ + } while (false) #define EMIT_NATIVE_VIPER_TYPE_ERROR(emit, ...) do { \ *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \ @@ -389,7 +301,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3); } else { assert(i == 3); // should be true; max 4 args is checked above - ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_4, i - REG_LOCAL_NUM); + ASM_MOV_LOCAL_REG(emit->as, i - REG_LOCAL_NUM, REG_ARG_4); } } #endif @@ -418,14 +330,14 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop #endif // set code_state.fun_bc - ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_1, offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t)); + ASM_MOV_LOCAL_REG(emit->as, offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t), REG_ARG_1); // set code_state.ip (offset from start of this function to prelude info) // XXX this encoding may change size - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), REG_ARG_1); + ASM_MOV_LOCAL_IMM_VIA(emit->as, offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), emit->prelude_offset, REG_ARG_1); // put address of code_state into first arg - ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1); + ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0); // call mp_setup_code_state to prepare code_state structure #if N_THUMB @@ -438,11 +350,11 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop // cache some locals in registers if (scope->num_locals > 0) { - ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 0, REG_LOCAL_1); + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, STATE_START + emit->n_state - 1 - 0); if (scope->num_locals > 1) { - ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 1, REG_LOCAL_2); + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_2, STATE_START + emit->n_state - 1 - 1); if (scope->num_locals > 2) { - ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 2, REG_LOCAL_3); + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_3, STATE_START + emit->n_state - 1 - 2); } } } @@ -606,7 +518,7 @@ STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) { stack_info_t *si = &emit->stack_info[i]; if (si->kind == STACK_REG && si->data.u_reg == reg_needed) { si->kind = STACK_VALUE; - ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i); + ASM_MOV_LOCAL_REG(emit->as, emit->stack_start + i, si->data.u_reg); } } } @@ -617,7 +529,7 @@ STATIC void need_reg_all(emit_t *emit) { stack_info_t *si = &emit->stack_info[i]; if (si->kind == STACK_REG) { si->kind = STACK_VALUE; - ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i); + ASM_MOV_LOCAL_REG(emit->as, emit->stack_start + i, si->data.u_reg); } } } @@ -629,7 +541,7 @@ STATIC void need_stack_settled(emit_t *emit) { if (si->kind == STACK_REG) { DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i); si->kind = STACK_VALUE; - ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i); + ASM_MOV_LOCAL_REG(emit->as, emit->stack_start + i, si->data.u_reg); } } for (int i = 0; i < emit->stack_size; i++) { @@ -637,7 +549,7 @@ STATIC void need_stack_settled(emit_t *emit) { if (si->kind == STACK_IMM) { DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i); si->kind = STACK_VALUE; - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + i, REG_TEMP0); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + i, si->data.u_imm, REG_TEMP0); } } } @@ -649,7 +561,7 @@ STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int re *vtype = si->vtype; switch (si->kind) { case STACK_VALUE: - ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - pos, reg_dest); + ASM_MOV_REG_LOCAL(emit->as, reg_dest, emit->stack_start + emit->stack_size - pos); break; case STACK_REG: @@ -659,7 +571,7 @@ STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int re break; case STACK_IMM: - ASM_MOV_IMM_TO_REG(emit->as, si->data.u_imm, reg_dest); + ASM_MOV_REG_IMM(emit->as, reg_dest, si->data.u_imm); break; } } @@ -671,7 +583,7 @@ STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) { si[0] = si[1]; if (si->kind == STACK_VALUE) { // if folded element was on the stack we need to put it in a register - ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - 1, reg_dest); + ASM_MOV_REG_LOCAL(emit->as, reg_dest, emit->stack_start + emit->stack_size - 1); si->kind = STACK_REG; si->data.u_reg = reg_dest; } @@ -765,30 +677,30 @@ STATIC void emit_call(emit_t *emit, mp_fun_kind_t fun_kind) { STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) { need_reg_all(emit); - ASM_MOV_IMM_TO_REG(emit->as, arg_val, arg_reg); + ASM_MOV_REG_IMM(emit->as, arg_reg, arg_val); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } // the first arg is stored in the code aligned on a mp_uint_t boundary STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) { need_reg_all(emit); - ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val, arg_reg); + ASM_MOV_REG_ALIGNED_IMM(emit->as, arg_reg, arg_val); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2) { need_reg_all(emit); - ASM_MOV_IMM_TO_REG(emit->as, arg_val1, arg_reg1); - ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2); + ASM_MOV_REG_IMM(emit->as, arg_reg1, arg_val1); + ASM_MOV_REG_IMM(emit->as, arg_reg2, arg_val2); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } // the first arg is stored in the code aligned on a mp_uint_t boundary STATIC void emit_call_with_3_imm_args_and_first_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2, mp_int_t arg_val3, int arg_reg3) { need_reg_all(emit); - ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val1, arg_reg1); - ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2); - ASM_MOV_IMM_TO_REG(emit->as, arg_val3, arg_reg3); + ASM_MOV_REG_ALIGNED_IMM(emit->as, arg_reg1, arg_val1); + ASM_MOV_REG_IMM(emit->as, arg_reg2, arg_val2); + ASM_MOV_REG_IMM(emit->as, arg_reg3, arg_val3); ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind); } @@ -808,19 +720,19 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de si->kind = STACK_VALUE; switch (si->vtype) { case VTYPE_PYOBJ: - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, si->data.u_imm, reg_dest); break; case VTYPE_BOOL: if (si->data.u_imm == 0) { - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, (mp_uint_t)mp_const_false, reg_dest); } else { - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, (mp_uint_t)mp_const_true, reg_dest); } si->vtype = VTYPE_PYOBJ; break; case VTYPE_INT: case VTYPE_UINT: - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm), emit->stack_start + emit->stack_size - 1 - i, reg_dest); + ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm), reg_dest); si->vtype = VTYPE_PYOBJ; break; default: @@ -838,9 +750,9 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i]; if (si->vtype != VTYPE_PYOBJ) { mp_uint_t local_num = emit->stack_start + emit->stack_size - 1 - i; - ASM_MOV_LOCAL_TO_REG(emit->as, local_num, REG_ARG_1); + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, local_num); emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, si->vtype, REG_ARG_2); // arg2 = type - ASM_MOV_REG_TO_LOCAL(emit->as, REG_RET, local_num); + ASM_MOV_LOCAL_REG(emit->as, local_num, REG_RET); si->vtype = VTYPE_PYOBJ; DEBUG_printf(" convert_native_to_obj(local_num=" UINT_FMT ")\n", local_num); } @@ -848,7 +760,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de // Adujust the stack for a pop of n_pop items, and load the stack pointer into reg_dest. adjust_stack(emit, -n_pop); - ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest); + ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, emit->stack_start + emit->stack_size); } // vtype of all n_push objects is VTYPE_PYOBJ @@ -858,7 +770,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_push(emit_t *emit, mp_uint_t reg_d emit->stack_info[emit->stack_size + i].kind = STACK_VALUE; emit->stack_info[emit->stack_size + i].vtype = VTYPE_PYOBJ; } - ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest); + ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, emit->stack_start + emit->stack_size); adjust_stack(emit, n_push); } @@ -881,7 +793,7 @@ STATIC void emit_native_import_name(emit_t *emit, qstr qst) { stack_info_t *top = peek_stack(emit, 0); if (top->vtype == VTYPE_PTR_NONE) { emit_pre_pop_discard(emit); - ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)mp_const_none, REG_ARG_2); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)mp_const_none); } else { vtype_kind_t vtype_fromlist; emit_pre_pop_reg(emit, &vtype_fromlist, REG_ARG_2); @@ -891,7 +803,7 @@ STATIC void emit_native_import_name(emit_t *emit, qstr qst) { // level argument should be an immediate integer top = peek_stack(emit, 0); assert(top->vtype == VTYPE_INT && top->kind == STACK_IMM); - ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_NEW_SMALL_INT(top->data.u_imm), REG_ARG_3); + ASM_MOV_REG_IMM(emit->as, REG_ARG_3, (mp_uint_t)MP_OBJ_NEW_SMALL_INT(top->data.u_imm)); emit_pre_pop_discard(emit); } else { @@ -925,6 +837,16 @@ STATIC void emit_native_import_star(emit_t *emit) { emit_post(emit); } +STATIC void emit_native_import(emit_t *emit, qstr qst, int kind) { + if (kind == MP_EMIT_IMPORT_NAME) { + emit_native_import_name(emit, qst); + } else if (kind == MP_EMIT_IMPORT_FROM) { + emit_native_import_from(emit, qst); + } else { + emit_native_import_star(emit); + } +} + STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) { DEBUG_printf("load_const_tok(tok=%u)\n", tok); emit_native_pre(emit); @@ -981,7 +903,7 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qst) { STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj) { emit_native_pre(emit); need_reg_single(emit, REG_RET, 0); - ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)obj, REG_RET); + ASM_MOV_REG_ALIGNED_IMM(emit->as, REG_RET, (mp_uint_t)obj); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1006,9 +928,9 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { } else { need_reg_single(emit, REG_TEMP0, 0); if (emit->do_viper_types) { - ASM_MOV_LOCAL_TO_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); + ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); } else { - ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0); + ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num); } emit_post_push_reg(emit, vtype, REG_TEMP0); } @@ -1026,33 +948,47 @@ STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } -STATIC void emit_native_load_name(emit_t *emit, qstr qst) { - DEBUG_printf("load_name(%s)\n", qstr_str(qst)); - emit_native_pre(emit); - emit_call_with_imm_arg(emit, MP_F_LOAD_NAME, qst, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); +STATIC void emit_native_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST) { + emit_native_load_fast(emit, qst, local_num); + } else { + emit_native_load_deref(emit, qst, local_num); + } } -STATIC void emit_native_load_global(emit_t *emit, qstr qst) { - DEBUG_printf("load_global(%s)\n", qstr_str(qst)); +STATIC void emit_native_load_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_LOAD_NAME); + MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_LOAD_GLOBAL); emit_native_pre(emit); - // check for builtin casting operators - if (emit->do_viper_types && qst == MP_QSTR_int) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_INT); - } else if (emit->do_viper_types && qst == MP_QSTR_uint) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_UINT); - } else if (emit->do_viper_types && qst == MP_QSTR_ptr) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR); - } else if (emit->do_viper_types && qst == MP_QSTR_ptr8) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR8); - } else if (emit->do_viper_types && qst == MP_QSTR_ptr16) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR16); - } else if (emit->do_viper_types && qst == MP_QSTR_ptr32) { - emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR32); + if (kind == MP_EMIT_IDOP_GLOBAL_NAME) { + DEBUG_printf("load_name(%s)\n", qstr_str(qst)); } else { - emit_call_with_imm_arg(emit, MP_F_LOAD_GLOBAL, qst, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + DEBUG_printf("load_global(%s)\n", qstr_str(qst)); + if (emit->do_viper_types) { + // check for builtin casting operators + if (qst == MP_QSTR_int) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_INT); + return; + } else if (qst == MP_QSTR_uint) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_UINT); + return; + } else if (qst == MP_QSTR_ptr) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR); + return; + } else if (qst == MP_QSTR_ptr8) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR8); + return; + } else if (qst == MP_QSTR_ptr16) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR16); + return; + } else if (qst == MP_QSTR_ptr32) { + emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR32); + return; + } + } } + emit_call_with_imm_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } STATIC void emit_native_load_attr(emit_t *emit, qstr qst) { @@ -1134,7 +1070,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base reg_base = reg_index; } @@ -1151,7 +1087,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base reg_base = reg_index; } @@ -1168,7 +1104,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value << 2, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base reg_base = reg_index; } @@ -1233,9 +1169,9 @@ STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) } else { emit_pre_pop_reg(emit, &vtype, REG_TEMP0); if (emit->do_viper_types) { - ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM); + ASM_MOV_LOCAL_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0); } else { - ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num); + ASM_MOV_LOCAL_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0); } } emit_post(emit); @@ -1266,25 +1202,33 @@ STATIC void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) emit_post(emit); } -STATIC void emit_native_store_name(emit_t *emit, qstr qst) { - // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type)) - vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, REG_ARG_2); - assert(vtype == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_STORE_NAME, qst, REG_ARG_1); // arg1 = name - emit_post(emit); +STATIC void emit_native_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST) { + emit_native_store_fast(emit, qst, local_num); + } else { + emit_native_store_deref(emit, qst, local_num); + } } -STATIC void emit_native_store_global(emit_t *emit, qstr qst) { - vtype_kind_t vtype = peek_vtype(emit, 0); - if (vtype == VTYPE_PYOBJ) { +STATIC void emit_native_store_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_STORE_NAME); + MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_STORE_GLOBAL); + if (kind == MP_EMIT_IDOP_GLOBAL_NAME) { + // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type)) + vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_2); + assert(vtype == VTYPE_PYOBJ); } else { - emit_pre_pop_reg(emit, &vtype, REG_ARG_1); - emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type - ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); + vtype_kind_t vtype = peek_vtype(emit, 0); + if (vtype == VTYPE_PYOBJ) { + emit_pre_pop_reg(emit, &vtype, REG_ARG_2); + } else { + emit_pre_pop_reg(emit, &vtype, REG_ARG_1); + emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET); + } } - emit_call_with_imm_arg(emit, MP_F_STORE_GLOBAL, qst, REG_ARG_1); // arg1 = name + emit_call_with_imm_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name emit_post(emit); } @@ -1354,7 +1298,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value); #if N_ARM asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); return; @@ -1375,7 +1319,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); #if N_ARM asm_arm_strh_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); return; @@ -1396,7 +1340,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) { break; } #endif - ASM_MOV_IMM_TO_REG(emit->as, index_value << 2, reg_index); + ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); #if N_ARM asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); return; @@ -1477,30 +1421,23 @@ STATIC void emit_native_store_subscr(emit_t *emit) { } } -STATIC void emit_native_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { - // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL - // to mark deleted vars but then every var would need to be checked on - // each access. Very inefficient, so just set value to None to enable GC. - emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE); - emit_native_store_fast(emit, qst, local_num); +STATIC void emit_native_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) { + if (kind == MP_EMIT_IDOP_LOCAL_FAST) { + // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL + // to mark deleted vars but then every var would need to be checked on + // each access. Very inefficient, so just set value to None to enable GC. + emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE); + emit_native_store_fast(emit, qst, local_num); + } else { + // TODO implement me! + } } -STATIC void emit_native_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) { - // TODO implement me! - (void)emit; - (void)qst; - (void)local_num; -} - -STATIC void emit_native_delete_name(emit_t *emit, qstr qst) { +STATIC void emit_native_delete_global(emit_t *emit, qstr qst, int kind) { + MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_DELETE_NAME); + MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_DELETE_GLOBAL); emit_native_pre(emit); - emit_call_with_imm_arg(emit, MP_F_DELETE_NAME, qst, REG_ARG_1); - emit_post(emit); -} - -STATIC void emit_native_delete_global(emit_t *emit, qstr qst) { - emit_native_pre(emit); - emit_call_with_imm_arg(emit, MP_F_DELETE_GLOBAL, qst, REG_ARG_1); + emit_call_with_imm_arg(emit, MP_F_DELETE_NAME + kind, qst, REG_ARG_1); emit_post(emit); } @@ -1520,6 +1457,26 @@ STATIC void emit_native_delete_subscr(emit_t *emit) { emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3); } +STATIC void emit_native_subscr(emit_t *emit, int kind) { + if (kind == MP_EMIT_SUBSCR_LOAD) { + emit_native_load_subscr(emit); + } else if (kind == MP_EMIT_SUBSCR_STORE) { + emit_native_store_subscr(emit); + } else { + emit_native_delete_subscr(emit); + } +} + +STATIC void emit_native_attr(emit_t *emit, qstr qst, int kind) { + if (kind == MP_EMIT_ATTR_LOAD) { + emit_native_load_attr(emit, qst); + } else if (kind == MP_EMIT_ATTR_STORE) { + emit_native_store_attr(emit, qst); + } else { + emit_native_delete_attr(emit, qst); + } +} + STATIC void emit_native_dup_top(emit_t *emit) { DEBUG_printf("dup_top\n"); vtype_kind_t vtype; @@ -1613,16 +1570,11 @@ STATIC void emit_native_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) emit_post(emit); } -STATIC void emit_native_break_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { +STATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { (void)except_depth; emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly } -STATIC void emit_native_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) { - (void)except_depth; - emit_native_jump(emit, label); // TODO properly -} - STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { // the context manager is on the top of the stack // stack: (..., ctx_mgr) @@ -1665,6 +1617,21 @@ STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) { // stack: (..., __exit__, self, as_value, nlr_buf, as_value) } +STATIC void emit_native_setup_block(emit_t *emit, mp_uint_t label, int kind) { + if (kind == MP_EMIT_SETUP_BLOCK_WITH) { + emit_native_setup_with(emit, label); + } else { + // Set up except and finally + emit_native_pre(emit); + // need to commit stack because we may jump elsewhere + need_stack_settled(emit); + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf + emit_call(emit, MP_F_NLR_PUSH); + ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label); + emit_post(emit); + } +} + STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { // note: label+1 is available as an auxiliary label @@ -1734,20 +1701,6 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { emit_native_label_assign(emit, label + 1); } -STATIC void emit_native_setup_except(emit_t *emit, mp_uint_t label) { - emit_native_pre(emit); - // need to commit stack because we may jump elsewhere - need_stack_settled(emit); - emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf - emit_call(emit, MP_F_NLR_PUSH); - ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label); - emit_post(emit); -} - -STATIC void emit_native_setup_finally(emit_t *emit, mp_uint_t label) { - emit_native_setup_except(emit, label); -} - STATIC void emit_native_end_finally(emit_t *emit) { // logic: // exc = pop_stack @@ -1773,7 +1726,7 @@ STATIC void emit_native_get_iter(emit_t *emit, bool use_stack) { emit_call(emit, MP_F_NATIVE_GETITER); } else { // mp_getiter will allocate the iter_buf on the heap - ASM_MOV_IMM_TO_REG(emit->as, 0, REG_ARG_2); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0); emit_call(emit, MP_F_NATIVE_GETITER); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1784,7 +1737,7 @@ STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS); adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS); emit_call(emit, MP_F_NATIVE_ITERNEXT); - ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_STOP_ITERATION, REG_TEMP1); + ASM_MOV_REG_IMM(emit->as, REG_TEMP1, (mp_uint_t)MP_OBJ_STOP_ITERATION); ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -1998,26 +1951,29 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { } } -STATIC void emit_native_build_tuple(emit_t *emit, mp_uint_t n_args) { +#if MICROPY_PY_BUILTINS_SLICE +STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args); +#endif + +STATIC void emit_native_build(emit_t *emit, mp_uint_t n_args, int kind) { // for viper: call runtime, with types of args // if wrapped in byte_array, or something, allocates memory and fills it + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_F_BUILD_TUPLE); + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_F_BUILD_LIST); + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_F_BUILD_MAP); + MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_F_BUILD_SET); + #if MICROPY_PY_BUILTINS_SLICE + if (kind == MP_EMIT_BUILD_SLICE) { + emit_native_build_slice(emit, n_args); + return; + } + #endif emit_native_pre(emit); - emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items - emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE, n_args, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple -} - -STATIC void emit_native_build_list(emit_t *emit, mp_uint_t n_args) { - emit_native_pre(emit); - emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items - emit_call_with_imm_arg(emit, MP_F_BUILD_LIST, n_args, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new list -} - -STATIC void emit_native_build_map(emit_t *emit, mp_uint_t n_args) { - emit_native_pre(emit); - emit_call_with_imm_arg(emit, MP_F_BUILD_MAP, n_args, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new map + if (kind == MP_EMIT_BUILD_TUPLE || kind == MP_EMIT_BUILD_LIST || kind == MP_EMIT_BUILD_SET) { + emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items + } + emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE + kind, n_args, REG_ARG_1); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple/list/map/set } STATIC void emit_native_store_map(emit_t *emit) { @@ -2030,15 +1986,6 @@ STATIC void emit_native_store_map(emit_t *emit) { emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map } -#if MICROPY_PY_BUILTINS_SET -STATIC void emit_native_build_set(emit_t *emit, mp_uint_t n_args) { - emit_native_pre(emit); - emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items - emit_call_with_imm_arg(emit, MP_F_BUILD_SET, n_args, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new set -} -#endif - #if MICROPY_PY_BUILTINS_SLICE STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) { DEBUG_printf("build_slice %d\n", n_args); @@ -2128,12 +2075,12 @@ STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_c emit_native_pre(emit); if (n_pos_defaults == 0 && n_kw_defaults == 0) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over); - ASM_MOV_IMM_TO_REG(emit->as, n_closed_over, REG_ARG_2); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, n_closed_over); } else { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over + 2); - ASM_MOV_IMM_TO_REG(emit->as, 0x100 | n_closed_over, REG_ARG_2); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0x100 | n_closed_over); } - ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)scope->raw_code, REG_ARG_1); + ASM_MOV_REG_ALIGNED_IMM(emit->as, REG_ARG_1, (mp_uint_t)scope->raw_code); ASM_CALL_IND(emit->as, mp_fun_table[MP_F_MAKE_CLOSURE_FROM_RAW_CODE], MP_F_MAKE_CLOSURE_FROM_RAW_CODE); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } @@ -2212,9 +2159,9 @@ STATIC void emit_native_return_value(emit_t *emit) { if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) { emit_pre_pop_discard(emit); if (emit->return_vtype == VTYPE_PYOBJ) { - ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)mp_const_none, REG_RET); + ASM_MOV_REG_IMM(emit->as, REG_RET, (mp_uint_t)mp_const_none); } else { - ASM_MOV_IMM_TO_REG(emit->as, 0, REG_RET); + ASM_MOV_REG_IMM(emit->as, REG_RET, 0); } } else { vtype_kind_t vtype; @@ -2245,16 +2192,12 @@ STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { emit_call(emit, MP_F_NATIVE_RAISE); } -STATIC void emit_native_yield_value(emit_t *emit) { +STATIC void emit_native_yield(emit_t *emit, int kind) { // not supported (for now) (void)emit; + (void)kind; mp_raise_NotImplementedError("native yield"); } -STATIC void emit_native_yield_from(emit_t *emit) { - // not supported (for now) - (void)emit; - mp_raise_NotImplementedError("native yield from"); -} STATIC void emit_native_start_except_handler(emit_t *emit) { // This instruction follows an nlr_pop, so the stack counter is back to zero, when really @@ -2280,41 +2223,29 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_set_source_line, { - emit_native_load_fast, - emit_native_load_deref, - emit_native_load_name, + emit_native_load_local, emit_native_load_global, }, { - emit_native_store_fast, - emit_native_store_deref, - emit_native_store_name, + emit_native_store_local, emit_native_store_global, }, { - emit_native_delete_fast, - emit_native_delete_deref, - emit_native_delete_name, + emit_native_delete_local, emit_native_delete_global, }, emit_native_label_assign, - emit_native_import_name, - emit_native_import_from, - emit_native_import_star, + emit_native_import, emit_native_load_const_tok, emit_native_load_const_small_int, emit_native_load_const_str, emit_native_load_const_obj, emit_native_load_null, - emit_native_load_attr, emit_native_load_method, emit_native_load_build_class, - emit_native_load_subscr, - emit_native_store_attr, - emit_native_store_subscr, - emit_native_delete_attr, - emit_native_delete_subscr, + emit_native_subscr, + emit_native_attr, emit_native_dup_top, emit_native_dup_top_two, emit_native_pop_top, @@ -2323,12 +2254,9 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_jump, emit_native_pop_jump_if, emit_native_jump_if_or_pop, - emit_native_break_loop, - emit_native_continue_loop, - emit_native_setup_with, + emit_native_unwind_jump, + emit_native_setup_block, emit_native_with_cleanup, - emit_native_setup_except, - emit_native_setup_finally, emit_native_end_finally, emit_native_get_iter, emit_native_for_iter, @@ -2337,16 +2265,8 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_pop_except, emit_native_unary_op, emit_native_binary_op, - emit_native_build_tuple, - emit_native_build_list, - emit_native_build_map, + emit_native_build, emit_native_store_map, - #if MICROPY_PY_BUILTINS_SET - emit_native_build_set, - #endif - #if MICROPY_PY_BUILTINS_SLICE - emit_native_build_slice, - #endif emit_native_store_comp, emit_native_unpack_sequence, emit_native_unpack_ex, @@ -2356,8 +2276,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_call_method, emit_native_return_value, emit_native_raise_varargs, - emit_native_yield_value, - emit_native_yield_from, + emit_native_yield, emit_native_start_except_handler, emit_native_end_except_handler, diff --git a/py/emitnthumb.c b/py/emitnthumb.c new file mode 100644 index 0000000000..2b68ca3a13 --- /dev/null +++ b/py/emitnthumb.c @@ -0,0 +1,15 @@ +// thumb specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_THUMB + +// this is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmthumb.h" + +#define N_THUMB (1) +#define EXPORT_FUN(name) emit_native_thumb_##name +#include "py/emitnative.c" + +#endif diff --git a/py/emitnx64.c b/py/emitnx64.c new file mode 100644 index 0000000000..b9800f636e --- /dev/null +++ b/py/emitnx64.c @@ -0,0 +1,15 @@ +// x64 specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_X64 + +// This is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmx64.h" + +#define N_X64 (1) +#define EXPORT_FUN(name) emit_native_x64_##name +#include "py/emitnative.c" + +#endif diff --git a/py/emitnx86.c b/py/emitnx86.c new file mode 100644 index 0000000000..5d2bbb267a --- /dev/null +++ b/py/emitnx86.c @@ -0,0 +1,68 @@ +// x86 specific stuff + +#include "py/mpconfig.h" +#include "py/runtime0.h" + +#if MICROPY_EMIT_X86 + +// This is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmx86.h" + +// x86 needs a table to know how many args a given function has +STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { + [MP_F_CONVERT_OBJ_TO_NATIVE] = 2, + [MP_F_CONVERT_NATIVE_TO_OBJ] = 2, + [MP_F_LOAD_NAME] = 1, + [MP_F_LOAD_GLOBAL] = 1, + [MP_F_LOAD_BUILD_CLASS] = 0, + [MP_F_LOAD_ATTR] = 2, + [MP_F_LOAD_METHOD] = 3, + [MP_F_LOAD_SUPER_METHOD] = 2, + [MP_F_STORE_NAME] = 2, + [MP_F_STORE_GLOBAL] = 2, + [MP_F_STORE_ATTR] = 3, + [MP_F_OBJ_SUBSCR] = 3, + [MP_F_OBJ_IS_TRUE] = 1, + [MP_F_UNARY_OP] = 2, + [MP_F_BINARY_OP] = 3, + [MP_F_BUILD_TUPLE] = 2, + [MP_F_BUILD_LIST] = 2, + [MP_F_LIST_APPEND] = 2, + [MP_F_BUILD_MAP] = 1, + [MP_F_STORE_MAP] = 3, + #if MICROPY_PY_BUILTINS_SET + [MP_F_BUILD_SET] = 2, + [MP_F_STORE_SET] = 2, + #endif + [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3, + [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3, + [MP_F_CALL_METHOD_N_KW] = 3, + [MP_F_CALL_METHOD_N_KW_VAR] = 3, + [MP_F_NATIVE_GETITER] = 2, + [MP_F_NATIVE_ITERNEXT] = 1, + [MP_F_NLR_PUSH] = 1, + [MP_F_NLR_POP] = 0, + [MP_F_NATIVE_RAISE] = 1, + [MP_F_IMPORT_NAME] = 3, + [MP_F_IMPORT_FROM] = 2, + [MP_F_IMPORT_ALL] = 1, + #if MICROPY_PY_BUILTINS_SLICE + [MP_F_NEW_SLICE] = 3, + #endif + [MP_F_UNPACK_SEQUENCE] = 3, + [MP_F_UNPACK_EX] = 3, + [MP_F_DELETE_NAME] = 1, + [MP_F_DELETE_GLOBAL] = 1, + [MP_F_NEW_CELL] = 1, + [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3, + [MP_F_SETUP_CODE_STATE] = 5, + [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2, + [MP_F_SMALL_INT_MODULO] = 2, +}; + +#define N_X86 (1) +#define EXPORT_FUN(name) emit_native_x86_##name +#include "py/emitnative.c" + +#endif diff --git a/py/emitnxtensa.c b/py/emitnxtensa.c new file mode 100644 index 0000000000..1a423e21eb --- /dev/null +++ b/py/emitnxtensa.c @@ -0,0 +1,15 @@ +// Xtensa specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_XTENSA + +// this is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmxtensa.h" + +#define N_XTENSA (1) +#define EXPORT_FUN(name) emit_native_xtensa_##name +#include "py/emitnative.c" + +#endif diff --git a/py/formatfloat.c b/py/formatfloat.c index 4228f99ff5..dc7fc1d1fd 100644 --- a/py/formatfloat.c +++ b/py/formatfloat.c @@ -258,7 +258,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch } // It can be that f was right on the edge of an entry in pos_pow needs to be reduced - if (f >= FPCONST(10.0)) { + if ((int)f >= 10) { e += 1; f *= FPCONST(0.1); } @@ -330,7 +330,11 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch // Print the digits of the mantissa for (int i = 0; i < num_digits; ++i, --dec) { int32_t d = (int32_t)f; - *s++ = '0' + d; + if (d < 0) { + *s++ = '0'; + } else { + *s++ = '0' + d; + } if (dec == 0 && prec > 0) { *s++ = '.'; } @@ -341,7 +345,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch // Round // If we print non-exponential format (i.e. 'f'), but a digit we're going // to round by (e) is too far away, then there's nothing to round. - if ((org_fmt != 'f' || e <= 1) && f >= FPCONST(5.0)) { + if ((org_fmt != 'f' || e <= num_digits) && f >= FPCONST(5.0)) { char *rs = s; rs--; while (1) { diff --git a/py/gc.c b/py/gc.c index 2c2354e4c0..1f5cd8d017 100755 --- a/py/gc.c +++ b/py/gc.c @@ -47,6 +47,10 @@ // make this 1 to dump the heap each time it changes #define EXTENSIVE_HEAP_PROFILING (0) +// make this 1 to zero out swept memory to more eagerly +// detect untraced object still in use +#define CLEAR_ON_SWEEP (0) + #define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD) #define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK) @@ -201,29 +205,22 @@ bool gc_is_locked(void) { && ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \ ) -// ptr should be of type void* -#define VERIFY_MARK_AND_PUSH(ptr) \ - do { \ - if (VERIFY_PTR(ptr)) { \ - size_t _block = BLOCK_FROM_PTR(ptr); \ - if (ATB_GET_KIND(_block) == AT_HEAD) { \ - /* an unmarked head, mark it, and push it on gc stack */ \ - DEBUG_printf("gc_mark(%p)\n", ptr); \ - ATB_HEAD_TO_MARK(_block); \ - if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { \ - *MP_STATE_MEM(gc_sp)++ = _block; \ - } else { \ - MP_STATE_MEM(gc_stack_overflow) = 1; \ - } \ - } \ - } \ - } while (0) - -STATIC void gc_drain_stack(void) { - while (MP_STATE_MEM(gc_sp) > MP_STATE_MEM(gc_stack)) { - // pop the next block off the stack - size_t block = *--MP_STATE_MEM(gc_sp); +#ifndef TRACE_MARK +#if DEBUG_PRINT +#define TRACE_MARK(block, ptr) DEBUG_printf("gc_mark(%p)\n", ptr) +#else +#define TRACE_MARK(block, ptr) +#endif +#endif +// Take the given block as the topmost block on the stack. Check all it's +// children: mark the unmarked child blocks and put those newly marked +// blocks on the stack. When all children have been checked, pop off the +// topmost block on the stack and repeat with that one. +STATIC void gc_mark_subtree(size_t block) { + // Start with the block passed in the argument. + size_t sp = 0; + for (;;) { // work out number of consecutive blocks in the chain starting with this one size_t n_blocks = 0; do { @@ -234,22 +231,41 @@ STATIC void gc_drain_stack(void) { void **ptrs = (void**)PTR_FROM_BLOCK(block); for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void*); i > 0; i--, ptrs++) { void *ptr = *ptrs; - VERIFY_MARK_AND_PUSH(ptr); + if (VERIFY_PTR(ptr)) { + // Mark and push this pointer + size_t childblock = BLOCK_FROM_PTR(ptr); + if (ATB_GET_KIND(childblock) == AT_HEAD) { + // an unmarked head, mark it, and push it on gc stack + TRACE_MARK(childblock, ptr); + ATB_HEAD_TO_MARK(childblock); + if (sp < MICROPY_ALLOC_GC_STACK_SIZE) { + MP_STATE_MEM(gc_stack)[sp++] = childblock; + } else { + MP_STATE_MEM(gc_stack_overflow) = 1; + } + } + } } + + // Are there any blocks on the stack? + if (sp == 0) { + break; // No, stack is empty, we're done. + } + + // pop the next block off the stack + block = MP_STATE_MEM(gc_stack)[--sp]; } } STATIC void gc_deal_with_stack_overflow(void) { while (MP_STATE_MEM(gc_stack_overflow)) { MP_STATE_MEM(gc_stack_overflow) = 0; - MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); // scan entire memory looking for blocks which have been marked but not their children for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) { // trace (again) if mark bit set if (ATB_GET_KIND(block) == AT_MARK) { - *MP_STATE_MEM(gc_sp)++ = block; - gc_drain_stack(); + gc_mark_subtree(block); } } } @@ -288,6 +304,9 @@ STATIC void gc_sweep(void) { #endif free_tail = 1; ATB_ANY_TO_FREE(block); + #if CLEAR_ON_SWEEP + memset((void*)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK); + #endif DEBUG_printf("gc_sweep(%x)\n", PTR_FROM_BLOCK(block)); #ifdef LOG_HEAP_ACTIVITY @@ -301,6 +320,9 @@ STATIC void gc_sweep(void) { case AT_TAIL: if (free_tail) { ATB_ANY_TO_FREE(block); + #if CLEAR_ON_SWEEP + memset((void*)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK); + #endif } break; @@ -319,19 +341,34 @@ void gc_collect_start(void) { MP_STATE_MEM(gc_alloc_amount) = 0; #endif MP_STATE_MEM(gc_stack_overflow) = 0; - MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); + // Trace root pointers. This relies on the root pointers being organised // correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals, // dict_globals, then the root pointer section of mp_state_vm. void **ptrs = (void**)(void*)&mp_state_ctx; - gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.qstr_last_chunk) / sizeof(void*)); + size_t root_start = offsetof(mp_state_ctx_t, thread.dict_locals); + size_t root_end = offsetof(mp_state_ctx_t, vm.qstr_last_chunk); + gc_collect_root(ptrs + root_start / sizeof(void*), (root_end - root_start) / sizeof(void*)); + + #if MICROPY_ENABLE_PYSTACK + // Trace root pointers from the Python stack. + ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start); + gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*)); + #endif } void gc_collect_root(void **ptrs, size_t len) { for (size_t i = 0; i < len; i++) { void *ptr = ptrs[i]; - VERIFY_MARK_AND_PUSH(ptr); - gc_drain_stack(); + if (VERIFY_PTR(ptr)) { + size_t block = BLOCK_FROM_PTR(ptr); + if (ATB_GET_KIND(block) == AT_HEAD) { + // An unmarked head: mark it, and mark all its children + TRACE_MARK(block, ptr); + ATB_HEAD_TO_MARK(block); + gc_mark_subtree(block); + } + } } } @@ -344,6 +381,13 @@ void gc_collect_end(void) { GC_EXIT(); } +void gc_sweep_all(void) { + GC_ENTER(); + MP_STATE_MEM(gc_lock_depth)++; + MP_STATE_MEM(gc_stack_overflow) = 0; + gc_collect_end(); +} + void gc_info(gc_info_t *info) { GC_ENTER(); info->total = MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start); @@ -437,6 +481,7 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) { if (!collected && MP_STATE_MEM(gc_alloc_amount) >= MP_STATE_MEM(gc_alloc_threshold)) { GC_EXIT(); gc_collect(); + collected = 1; GC_ENTER(); collected = true; } @@ -748,27 +793,18 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { void *ptr = ptr_in; - // sanity check the ptr - if (!VERIFY_PTR(ptr)) { - return NULL; - } - - // get first block - size_t block = BLOCK_FROM_PTR(ptr); - GC_ENTER(); - // sanity check the ptr is pointing to the head of a block - if (ATB_GET_KIND(block) != AT_HEAD) { - GC_EXIT(); - return NULL; - } - if (MP_STATE_MEM(gc_lock_depth) > 0) { GC_EXIT(); return NULL; } + // get the GC block number corresponding to this pointer + assert(VERIFY_PTR(ptr)); + size_t block = BLOCK_FROM_PTR(ptr); + assert(ATB_GET_KIND(block) == AT_HEAD); + // compute number of new blocks that are requested size_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK; diff --git a/py/gc.h b/py/gc.h index e5878e1eed..64f4b0d177 100644 --- a/py/gc.h +++ b/py/gc.h @@ -46,6 +46,10 @@ void gc_collect_root(void **ptrs, size_t len); void gc_collect_end(void); void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived); + +// Use this function to sweep the whole heap and run all finalisers +void gc_sweep_all(void); + void gc_free(void *ptr); // does not call finaliser size_t gc_nbytes(const void *ptr); bool gc_has_finaliser(const void *ptr); diff --git a/py/grammar.h b/py/grammar.h index 6abb1de8c0..5a5b682acc 100644 --- a/py/grammar.h +++ b/py/grammar.h @@ -122,8 +122,8 @@ DEF_RULE_NC(augassign, or(12), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DE DEF_RULE(del_stmt, c(del_stmt), and(2), tok(KW_DEL), rule(exprlist)) DEF_RULE(pass_stmt, c(generic_all_nodes), and(1), tok(KW_PASS)) DEF_RULE_NC(flow_stmt, or(5), rule(break_stmt), rule(continue_stmt), rule(return_stmt), rule(raise_stmt), rule(yield_stmt)) -DEF_RULE(break_stmt, c(break_stmt), and(1), tok(KW_BREAK)) -DEF_RULE(continue_stmt, c(continue_stmt), and(1), tok(KW_CONTINUE)) +DEF_RULE(break_stmt, c(break_cont_stmt), and(1), tok(KW_BREAK)) +DEF_RULE(continue_stmt, c(break_cont_stmt), and(1), tok(KW_CONTINUE)) DEF_RULE(return_stmt, c(return_stmt), and(2), tok(KW_RETURN), opt_rule(testlist)) DEF_RULE(yield_stmt, c(yield_stmt), and(1), rule(yield_expr)) DEF_RULE(raise_stmt, c(raise_stmt), and(2), tok(KW_RAISE), opt_rule(raise_stmt_arg)) @@ -157,8 +157,8 @@ DEF_RULE_NC(as_name, and_ident(2), tok(KW_AS), tok(NAME)) DEF_RULE_NC(import_as_names, list_with_end, rule(import_as_name), tok(DEL_COMMA)) DEF_RULE_NC(dotted_as_names, list, rule(dotted_as_name), tok(DEL_COMMA)) DEF_RULE_NC(dotted_name, list, tok(NAME), tok(DEL_PERIOD)) -DEF_RULE(global_stmt, c(global_stmt), and(2), tok(KW_GLOBAL), rule(name_list)) -DEF_RULE(nonlocal_stmt, c(nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list)) +DEF_RULE(global_stmt, c(global_nonlocal_stmt), and(2), tok(KW_GLOBAL), rule(name_list)) +DEF_RULE(nonlocal_stmt, c(global_nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list)) DEF_RULE_NC(name_list, list, tok(NAME), tok(DEL_COMMA)) DEF_RULE(assert_stmt, c(assert_stmt), and(3), tok(KW_ASSERT), rule(test), opt_rule(assert_stmt_extra)) DEF_RULE_NC(assert_stmt_extra, and_ident(2), tok(DEL_COMMA), rule(test)) @@ -231,8 +231,8 @@ DEF_RULE(lambdef_nocond, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(vara // power: atom_expr ['**' factor] // atom_expr: 'await' atom trailer* | atom trailer* -DEF_RULE(or_test, c(or_test), list, rule(and_test), tok(KW_OR)) -DEF_RULE(and_test, c(and_test), list, rule(not_test), tok(KW_AND)) +DEF_RULE(or_test, c(or_and_test), list, rule(and_test), tok(KW_OR)) +DEF_RULE(and_test, c(or_and_test), list, rule(not_test), tok(KW_AND)) DEF_RULE_NC(not_test, or(2), rule(not_test_2), rule(comparison)) DEF_RULE(not_test_2, c(not_test_2), and(2), tok(KW_NOT), rule(not_test)) DEF_RULE(comparison, c(comparison), list, rule(expr), rule(comp_op)) @@ -241,9 +241,9 @@ DEF_RULE_NC(comp_op_not_in, and(2), tok(KW_NOT), tok(KW_IN)) DEF_RULE_NC(comp_op_is, and(2), tok(KW_IS), opt_rule(comp_op_is_not)) DEF_RULE_NC(comp_op_is_not, and(1), tok(KW_NOT)) DEF_RULE(star_expr, c(star_expr), and(2), tok(OP_STAR), rule(expr)) -DEF_RULE(expr, c(expr), list, rule(xor_expr), tok(OP_PIPE)) -DEF_RULE(xor_expr, c(xor_expr), list, rule(and_expr), tok(OP_CARET)) -DEF_RULE(and_expr, c(and_expr), list, rule(shift_expr), tok(OP_AMPERSAND)) +DEF_RULE(expr, c(binary_op), list, rule(xor_expr), tok(OP_PIPE)) +DEF_RULE(xor_expr, c(binary_op), list, rule(and_expr), tok(OP_CARET)) +DEF_RULE(and_expr, c(binary_op), list, rule(shift_expr), tok(OP_AMPERSAND)) DEF_RULE(shift_expr, c(term), list, rule(arith_expr), rule(shift_op)) DEF_RULE_NC(shift_op, or(2), tok(OP_DBL_LESS), tok(OP_DBL_MORE)) DEF_RULE(arith_expr, c(term), list, rule(term), rule(arith_op)) @@ -290,8 +290,8 @@ DEF_RULE(trailer_period, c(trailer_period), and(2), tok(DEL_PERIOD), tok(NAME)) #if MICROPY_PY_BUILTINS_SLICE DEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(subscript), tok(DEL_COMMA)) DEF_RULE_NC(subscript, or(2), rule(subscript_3), rule(subscript_2)) -DEF_RULE(subscript_2, c(subscript_2), and_ident(2), rule(test), opt_rule(subscript_3)) -DEF_RULE(subscript_3, c(subscript_3), and(2), tok(DEL_COLON), opt_rule(subscript_3b)) +DEF_RULE(subscript_2, c(subscript), and_ident(2), rule(test), opt_rule(subscript_3)) +DEF_RULE(subscript_3, c(subscript), and(2), tok(DEL_COLON), opt_rule(subscript_3b)) DEF_RULE_NC(subscript_3b, or(2), rule(subscript_3c), rule(subscript_3d)) DEF_RULE_NC(subscript_3c, and(2), tok(DEL_COLON), opt_rule(test)) DEF_RULE_NC(subscript_3d, and_ident(2), rule(test), opt_rule(sliceop)) diff --git a/py/lexer.c b/py/lexer.c index 6017d69d6d..e161700b16 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -590,6 +590,8 @@ void mp_lexer_to_next(mp_lexer_t *lex) { } vstr_add_char(&lex->vstr, CUR_CHAR(lex)); next_char(lex); + } else if (is_char(lex, '_')) { + next_char(lex); } else { break; } diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 38fde1a9c6..3c0a609092 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -114,6 +114,9 @@ def parse_input_headers(infiles): if ident == "": # Sort empty qstr above all still order = -200000 + elif ident == "__dir__": + # Put __dir__ after empty qstr for builtin dir() to work + order = -190000 elif ident.startswith("__"): order -= 100000 qstrs[ident] = (order, ident, qstr) diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index 0a45c585a6..4253c1147b 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -73,12 +73,16 @@ def qstr_unescape(qstr): return qstr def process_file(f): + re_line = re.compile(r"#[line]*\s\d+\s\"([^\"]+)\"") + re_qstr = re.compile(r'MP_QSTR_[_a-zA-Z0-9]+') output = [] last_fname = None for line in f: + if line.isspace(): + continue # match gcc-like output (# n "file") and msvc-like output (#line n "file") - if line and (line[0:2] == "# " or line[0:5] == "#line"): - m = re.match(r"#[line]*\s\d+\s\"([^\"]+)\"", line) + if line.startswith(('# ', '#line')): + m = re_line.match(line) assert m is not None fname = m.group(1) if not fname.endswith(".c"): @@ -88,7 +92,7 @@ def process_file(f): output = [] last_fname = fname continue - for match in re.findall(r'MP_QSTR_[_a-zA-Z0-9]+', line): + for match in re_qstr.findall(line): name = match.replace('MP_QSTR_', '') if name not in QSTRING_BLACK_LIST: output.append('Q(' + qstr_unescape(name) + ')') diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py index 1f82d59339..89a604aebf 100644 --- a/py/makeversionhdr.py +++ b/py/makeversionhdr.py @@ -100,7 +100,7 @@ def make_version_header(filename): # Only write the file if we need to if write_file: - print("Generating %s" % filename) + print("GEN %s" % filename) with open(filename, 'w') as f: f.write(file_data) diff --git a/py/malloc.c b/py/malloc.c index d6983ffdfc..f190582ab2 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -39,6 +39,9 @@ #endif #if MICROPY_MEM_STATS +#if !MICROPY_MALLOC_USES_ALLOCATED_SIZE +#error MICROPY_MEM_STATS requires MICROPY_MALLOC_USES_ALLOCATED_SIZE +#endif #define UPDATE_PEAK() { if (MP_STATE_MEM(current_bytes_allocated) > MP_STATE_MEM(peak_bytes_allocated)) MP_STATE_MEM(peak_bytes_allocated) = MP_STATE_MEM(current_bytes_allocated); } #endif @@ -117,9 +120,6 @@ void *m_malloc_with_finaliser(size_t num_bytes) { void *m_malloc0(size_t num_bytes, bool long_lived) { void *ptr = m_malloc(num_bytes, long_lived); - if (ptr == NULL && num_bytes != 0) { - m_malloc_fail(num_bytes); - } // If this config is set then the GC clears all memory, so we don't need to. #if !MICROPY_GC_CONSERVATIVE_CLEAR memset(ptr, 0, num_bytes); @@ -147,7 +147,11 @@ void *m_realloc(void *ptr, size_t new_num_bytes) { MP_STATE_MEM(current_bytes_allocated) += diff; UPDATE_PEAK(); #endif + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr); + #else + DEBUG_printf("realloc %p, %d : %p\n", ptr, new_num_bytes, new_ptr); + #endif return new_ptr; } @@ -171,7 +175,11 @@ void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) { UPDATE_PEAK(); } #endif + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr); + #else + DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, new_num_bytes, new_ptr); + #endif return new_ptr; } @@ -184,7 +192,11 @@ void m_free(void *ptr) { #if MICROPY_MEM_STATS MP_STATE_MEM(current_bytes_allocated) -= num_bytes; #endif + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE DEBUG_printf("free %p, %d\n", ptr, num_bytes); + #else + DEBUG_printf("free %p\n", ptr); + #endif } #if MICROPY_MEM_STATS diff --git a/py/map.c b/py/map.c index 4f76b9b16c..6abf4853f1 100644 --- a/py/map.c +++ b/py/map.c @@ -33,6 +33,13 @@ #include "py/misc.h" #include "py/runtime.h" +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#else // don't print debugging info +#define DEBUG_PRINT (0) +#define DEBUG_printf(...) (void)0 +#endif + // Fixed empty map. Useful when need to call kw-receiving functions // without any keywords from C, etc. const mp_map_t mp_const_empty_map = { @@ -114,6 +121,7 @@ void mp_map_clear(mp_map_t *map) { STATIC void mp_map_rehash(mp_map_t *map) { size_t old_alloc = map->alloc; size_t new_alloc = get_hash_alloc_greater_or_equal_to(map->alloc + 1); + DEBUG_printf("mp_map_rehash(%p): " UINT_FMT " -> " UINT_FMT "\n", map, old_alloc, new_alloc); mp_map_elem_t *old_table = map->table; mp_map_elem_t *new_table = m_new0(mp_map_elem_t, new_alloc); // If we reach this point, table resizing succeeded, now we can edit the old map. @@ -162,6 +170,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t if (map->is_ordered) { for (mp_map_elem_t *elem = &map->table[0], *top = &map->table[map->used]; elem < top; elem++) { if (elem->key == index || (!compare_only_ptrs && mp_obj_equal(elem->key, index))) { + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT if (MP_UNLIKELY(lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND)) { // remove the found element by moving the rest of the array down mp_obj_t value = elem->value; @@ -172,9 +181,11 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t elem->key = MP_OBJ_NULL; elem->value = value; } + #endif return elem; } } + #if MICROPY_PY_COLLECTIONS_ORDEREDDICT if (MP_LIKELY(lookup_kind != MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)) { return NULL; } @@ -190,6 +201,9 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t map->all_keys_are_qstrs = 0; } return elem; + #else + return NULL; + #endif } // map is a hash table (not an ordered array), so do a hash lookup diff --git a/py/misc.h b/py/misc.h index d9a8efe7f8..673568f226 100644 --- a/py/misc.h +++ b/py/misc.h @@ -52,6 +52,9 @@ typedef unsigned int uint; #define _MP_STRINGIFY(x) #x #define MP_STRINGIFY(x) _MP_STRINGIFY(x) +// Static assertion macro +#define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)])) + /** memory allocation ******************************************/ // TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element) @@ -70,8 +73,10 @@ typedef unsigned int uint; #define m_new_ll_obj_var_maybe(obj_type, var_type, var_num) ((obj_type*)m_malloc_maybe(sizeof(obj_type) + sizeof(var_type) * (var_num), true)) #if MICROPY_ENABLE_FINALISER #define m_new_obj_with_finaliser(type) ((type*)(m_malloc_with_finaliser(sizeof(type)))) +#define m_new_obj_var_with_finaliser(type, var_type, var_num) ((type*)m_malloc_with_finaliser(sizeof(type) + sizeof(var_type) * (var_num))) #else #define m_new_obj_with_finaliser(type) m_new_obj(type) +#define m_new_obj_var_with_finaliser(type, var_type, var_num) m_new_obj_var(type, var_type, var_num) #endif #if MICROPY_MALLOC_USES_ALLOCATED_SIZE #define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num)))) @@ -126,8 +131,15 @@ typedef uint32_t unichar; typedef uint unichar; #endif +#if MICROPY_PY_BUILTINS_STR_UNICODE unichar utf8_get_char(const byte *s); const byte *utf8_next_char(const byte *s); +size_t utf8_charlen(const byte *str, size_t len); +#else +static inline unichar utf8_get_char(const byte *s) { return *s; } +static inline const byte *utf8_next_char(const byte *s) { return s + 1; } +static inline size_t utf8_charlen(const byte *str, size_t len) { (void)str; return len; } +#endif bool unichar_isspace(unichar c); bool unichar_isalpha(unichar c); @@ -140,7 +152,6 @@ bool unichar_islower(unichar c); unichar unichar_tolower(unichar c); unichar unichar_toupper(unichar c); mp_uint_t unichar_xdigit_value(unichar c); -mp_uint_t unichar_charlen(const char *str, mp_uint_t len); #define UTF8_IS_NONASCII(ch) ((ch) & 0x80) #define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80) @@ -203,20 +214,6 @@ int DEBUG_printf(const char *fmt, ...); extern mp_uint_t mp_verbose_flag; -// This is useful for unicode handling. Some CPU archs has -// special instructions for efficient implementation of this -// function (e.g. CLZ on ARM). -// NOTE: this function is unused at the moment -#ifndef count_lead_ones -static inline mp_uint_t count_lead_ones(byte val) { - mp_uint_t c = 0; - for (byte mask = 0x80; val & mask; mask >>= 1) { - c++; - } - return c; -} -#endif - /** float internals *************/ #if MICROPY_PY_BUILTINS_FLOAT diff --git a/py/mkenv.mk b/py/mkenv.mk index 5f8cd902bf..1b316c39df 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -67,9 +67,9 @@ CXX += -m32 LD += -m32 endif -MAKE_FROZEN = $(TOP)/tools/make-frozen.py +MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py MPY_CROSS = $(TOP)/mpy-cross/mpy-cross -MPY_TOOL = $(TOP)/tools/mpy-tool.py +MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py all: diff --git a/py/mkrules.mk b/py/mkrules.mk index ed66da64ba..57a51194a8 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -46,16 +46,14 @@ vpath %.c . $(TOP) $(BUILD)/%.o: %.c $(call compile_c) +QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR + # frozen.c and frozen_mpy.c are created in $(BUILD), so use our rule # for those as well. vpath %.c . $(BUILD) $(BUILD)/%.o: %.c $(call compile_c) -# List all native flags since the current build system doesn't have -# the MicroPython configuration available. However, these flags are -# needed to extract all qstrings -QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB -DN_ARM -DN_XTENSA QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp vpath %.c . $(TOP) @@ -75,9 +73,13 @@ $(BUILD)/%.pp: %.c # to get built before we try to compile any of them. $(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h -$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) | $(HEADER_BUILD)/mpversion.h +# The logic for qstr regeneration is: +# - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^) +# - else, if list of newer prerequisites ($?) is not empty, then process just these ($?) +# - else, process all source files ($^) [this covers "make -B" which can set $? to empty] +$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h $(ECHO) "GEN $@" - $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $?,$?,$^) >$(HEADER_BUILD)/qstr.i.last; + $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) >$(HEADER_BUILD)/qstr.i.last; $(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last $(STEPECHO) "GEN $@" @@ -130,7 +132,7 @@ xargs -n1 "$(abspath $(MPY_CROSS))" $(MPY_CROSS_FLAGS) # if the default will not work (mpz is the default). $(BUILD)/frozen_mpy.c: $(BUILD)/frozen_mpy $(BUILD)/genhdr/qstrdefs.generated.h $(STEPECHO) "Creating $@" - $(Q)$(PYTHON) $(MPY_TOOL) $(MPY_TOOL_LONGINT_IMPL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(shell $(FIND) -L $(BUILD)/frozen_mpy -type f -name '*.mpy') > $@ + $(Q)$(MPY_TOOL) $(MPY_TOOL_LONGINT_IMPL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(shell $(FIND) -L $(BUILD)/frozen_mpy -type f -name '*.mpy') > $@ endif ifneq ($(PROG),) @@ -171,6 +173,27 @@ clean: $(RM) -rf $(BUILD) $(CLEAN_EXTRA) .PHONY: clean +# Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup. +# We run rmdir below to avoid empty backup dir (it will silently fail if backup +# is non-empty). +clean-frozen: + if [ -n "$(FROZEN_MPY_DIR)" ]; then \ + backup_dir=$(FROZEN_MPY_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \ + cd $(FROZEN_MPY_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \ + | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \ + rmdir ../$$backup_dir 2>/dev/null || true; \ + git clean -d -f .; \ + fi + + if [ -n "$(FROZEN_DIR)" ]; then \ + backup_dir=$(FROZEN_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \ + cd $(FROZEN_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \ + | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \ + rmdir ../$$backup_dir 2>/dev/null || true; \ + git clean -d -f .; \ + fi +.PHONY: clean-frozen + print-cfg: $(ECHO) "PY_SRC = $(PY_SRC)" $(ECHO) "BUILD = $(BUILD)" diff --git a/py/modbuiltins.c b/py/modbuiltins.c index cea87b1813..eb1a172045 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -137,7 +137,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable); STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { #if MICROPY_PY_BUILTINS_STR_UNICODE mp_uint_t c = mp_obj_get_int(o_in); - char str[4]; + uint8_t str[4]; int len = 0; if (c < 0x80) { *str = c; len = 1; @@ -159,12 +159,12 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { } else { mp_raise_ValueError("chr() arg not in range(0x110000)"); } - return mp_obj_new_str(str, len, true); + return mp_obj_new_str_via_qstr((char*)str, len); #else mp_int_t ord = mp_obj_get_int(o_in); if (0 <= ord && ord <= 0xff) { - char str[1] = {ord}; - return mp_obj_new_str(str, 1, true); + uint8_t str[1] = {ord}; + return mp_obj_new_str_via_qstr((char*)str, 1); } else { mp_raise_ValueError("chr() arg not in range(256)"); } @@ -173,46 +173,31 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr); STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { - // TODO make this function more general and less of a hack - - mp_obj_dict_t *dict = NULL; - mp_map_t *members = NULL; - if (n_args == 0) { - // make a list of names in the local name space - dict = mp_locals_get(); - } else { // n_args == 1 - // make a list of names in the given object - if (MP_OBJ_IS_TYPE(args[0], &mp_type_module)) { - dict = mp_obj_module_get_globals(args[0]); - } else { - mp_obj_type_t *type; - if (MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { - type = MP_OBJ_TO_PTR(args[0]); - } else { - type = mp_obj_get_type(args[0]); - } - if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) { - dict = type->locals_dict; - } - } - if (mp_obj_is_instance_type(mp_obj_get_type(args[0]))) { - mp_obj_instance_t *inst = MP_OBJ_TO_PTR(args[0]); - members = &inst->members; - } - } - mp_obj_t dir = mp_obj_new_list(0, NULL); - if (dict != NULL) { + if (n_args == 0) { + // Make a list of names in the local namespace + mp_obj_dict_t *dict = mp_locals_get(); for (size_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { mp_obj_list_append(dir, dict->map.table[i].key); } } - } - if (members != NULL) { - for (size_t i = 0; i < members->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(members, i)) { - mp_obj_list_append(dir, members->table[i].key); + } else { // n_args == 1 + // Make a list of names in the given object + // Implemented by probing all possible qstrs with mp_load_method_maybe + size_t nqstr = QSTR_TOTAL(); + for (size_t i = MP_QSTR_ + 1; i < nqstr; ++i) { + mp_obj_t dest[2]; + mp_load_method_protected(args[0], i, dest, false); + if (dest[0] != MP_OBJ_NULL) { + #if MICROPY_PY_ALL_SPECIAL_METHODS + // Support for __dir__: see if we can dispatch to this special method + // This relies on MP_QSTR__dir__ being first after MP_QSTR_ + if (i == MP_QSTR___dir__ && dest[1] != MP_OBJ_NULL) { + return mp_call_method_n_kw(0, 0, dest); + } + #endif + mp_obj_list_append(dir, MP_OBJ_NEW_QSTR(i)); } } } @@ -343,19 +328,19 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct); STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { size_t len; - const char *str = mp_obj_str_get_data(o_in, &len); + const byte *str = (const byte*)mp_obj_str_get_data(o_in, &len); #if MICROPY_PY_BUILTINS_STR_UNICODE if (MP_OBJ_IS_STR(o_in)) { - len = unichar_charlen(str, len); + len = utf8_charlen(str, len); if (len == 1) { - return mp_obj_new_int(utf8_get_char((const byte*)str)); + return mp_obj_new_int(utf8_get_char(str)); } } else #endif { // a bytes object, or a str without unicode support (don't sign extend the char) if (len == 1) { - return MP_OBJ_NEW_SMALL_INT(((const byte*)str)[0]); + return MP_OBJ_NEW_SMALL_INT(str[0]); } } @@ -383,46 +368,52 @@ STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow); -STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - mp_map_elem_t *sep_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_MAP_LOOKUP); - mp_map_elem_t *end_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_MAP_LOOKUP); - const char *sep_data = " "; - size_t sep_len = 1; - const char *end_data = "\n"; - size_t end_len = 1; - if (sep_elem != NULL && sep_elem->value != mp_const_none) { - sep_data = mp_obj_str_get_data(sep_elem->value, &sep_len); - } - if (end_elem != NULL && end_elem->value != mp_const_none) { - end_data = mp_obj_str_get_data(end_elem->value, &end_len); - } - #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - void *stream_obj = &mp_sys_stdout_obj; - mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP); - if (file_elem != NULL && file_elem->value != mp_const_none) { - stream_obj = MP_OBJ_TO_PTR(file_elem->value); // XXX may not be a concrete object - } +STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sep, ARG_end, ARG_file }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__space_)} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__0x0a_)} }, + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + { MP_QSTR_file, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_sys_stdout_obj)} }, + #endif + }; - mp_print_t print = {stream_obj, mp_stream_write_adaptor}; + // parse args (a union is used to reduce the amount of C stack that is needed) + union { + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + size_t len[2]; + } u; + mp_arg_parse_all(0, NULL, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, u.args); + + #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES + mp_get_stream_raise(u.args[ARG_file].u_obj, MP_STREAM_OP_WRITE); + mp_print_t print = {MP_OBJ_TO_PTR(u.args[ARG_file].u_obj), mp_stream_write_adaptor}; #endif + + // extract the objects first because we are going to use the other part of the union + mp_obj_t sep = u.args[ARG_sep].u_obj; + mp_obj_t end = u.args[ARG_end].u_obj; + const char *sep_data = mp_obj_str_get_data(sep, &u.len[0]); + const char *end_data = mp_obj_str_get_data(end, &u.len[1]); + for (size_t i = 0; i < n_args; i++) { if (i > 0) { #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - mp_stream_write_adaptor(stream_obj, sep_data, sep_len); + mp_stream_write_adaptor(print.data, sep_data, u.len[0]); #else - mp_print_strn(&mp_plat_print, sep_data, sep_len, 0, 0, 0); + mp_print_strn(&mp_plat_print, sep_data, u.len[0], 0, 0, 0); #endif } #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - mp_obj_print_helper(&print, args[i], PRINT_STR); + mp_obj_print_helper(&print, pos_args[i], PRINT_STR); #else - mp_obj_print_helper(&mp_plat_print, args[i], PRINT_STR); + mp_obj_print_helper(&mp_plat_print, pos_args[i], PRINT_STR); #endif } #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES - mp_stream_write_adaptor(stream_obj, end_data, end_len); + mp_stream_write_adaptor(print.data, end_data, u.len[1]); #else - mp_print_strn(&mp_plat_print, end_data, end_len, 0, 0, 0); + mp_print_strn(&mp_plat_print, end_data, u.len[1], 0, 0, 0); #endif return mp_const_none; } @@ -454,19 +445,46 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr); STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { mp_obj_t o_in = args[0]; if (MP_OBJ_IS_INT(o_in)) { - return o_in; + if (n_args <= 1) { + return o_in; + } + + #if !MICROPY_PY_BUILTINS_ROUND_INT + mp_raise_NotImplementedError(NULL); + #else + mp_int_t num_dig = mp_obj_get_int(args[1]); + if (num_dig >= 0) { + return o_in; + } + + mp_obj_t mult = mp_binary_op(MP_BINARY_OP_POWER, MP_OBJ_NEW_SMALL_INT(10), MP_OBJ_NEW_SMALL_INT(-num_dig)); + mp_obj_t half_mult = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, mult, MP_OBJ_NEW_SMALL_INT(2)); + mp_obj_t modulo = mp_binary_op(MP_BINARY_OP_MODULO, o_in, mult); + mp_obj_t rounded = mp_binary_op(MP_BINARY_OP_SUBTRACT, o_in, modulo); + if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, half_mult, modulo))) { + return rounded; + } else if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, modulo, half_mult))) { + return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult); + } else { + // round to even number + mp_obj_t floor = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, o_in, mult); + if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_AND, floor, MP_OBJ_NEW_SMALL_INT(1)))) { + return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult); + } else { + return rounded; + } + } + #endif } #if MICROPY_PY_BUILTINS_FLOAT - mp_int_t num_dig = 0; + mp_float_t val = mp_obj_get_float(o_in); if (n_args > 1) { - num_dig = mp_obj_get_int(args[1]); - mp_float_t val = mp_obj_get_float(o_in); + mp_int_t num_dig = mp_obj_get_int(args[1]); mp_float_t mult = MICROPY_FLOAT_C_FUN(pow)(10, num_dig); // TODO may lead to overflow mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val * mult) / mult; return mp_obj_new_float(rounded); } - mp_float_t val = mp_obj_get_float(o_in); mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val); return mp_obj_new_int_from_float(rounded); #else @@ -543,14 +561,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr); STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { qstr attr = mp_obj_str_get_qstr(attr_in); - mp_obj_t dest[2]; - // TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr - // explicitly says "This is implemented by calling getattr(object, name) and seeing - // whether it raises an AttributeError or not.", so we should explicitly wrap this - // in nlr_push and handle exception. - mp_load_method_maybe(object_in, attr, dest); - + mp_load_method_protected(object_in, attr, dest, false); return mp_obj_new_bool(dest[0] != MP_OBJ_NULL); } MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr); diff --git a/py/modcollections.c b/py/modcollections.c index 837ec2f92d..91e7355281 100644 --- a/py/modcollections.c +++ b/py/modcollections.c @@ -30,6 +30,9 @@ STATIC const mp_rom_map_elem_t mp_module_collections_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_collections) }, + #if MICROPY_PY_COLLECTIONS_DEQUE + { MP_ROM_QSTR(MP_QSTR_deque), MP_ROM_PTR(&mp_type_deque) }, + #endif { MP_ROM_QSTR(MP_QSTR_namedtuple), MP_ROM_PTR(&mp_namedtuple_obj) }, #if MICROPY_PY_COLLECTIONS_ORDEREDDICT { MP_ROM_QSTR(MP_QSTR_OrderedDict), MP_ROM_PTR(&mp_type_ordereddict) }, diff --git a/py/modio.c b/py/modio.c index 9263b5949b..9b09de96e4 100644 --- a/py/modio.c +++ b/py/modio.c @@ -30,6 +30,8 @@ #include "py/runtime.h" #include "py/builtin.h" #include "py/stream.h" +#include "py/binary.h" +#include "py/objarray.h" #include "py/objstringio.h" #include "py/frozenmod.h" @@ -38,6 +40,70 @@ extern const mp_obj_type_t mp_type_fileio; extern const mp_obj_type_t mp_type_textio; +#if MICROPY_PY_IO_IOBASE + +STATIC const mp_obj_type_t mp_type_iobase; + +STATIC mp_obj_base_t iobase_singleton = {&mp_type_iobase}; + +STATIC mp_obj_t iobase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type; + (void)n_args; + (void)n_kw; + (void)args; + return MP_OBJ_FROM_PTR(&iobase_singleton); +} + +STATIC mp_uint_t iobase_read_write(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode, qstr qst) { + mp_obj_t dest[3]; + mp_load_method(obj, qst, dest); + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, size, buf}; + dest[2] = MP_OBJ_FROM_PTR(&ar); + mp_obj_t ret = mp_call_method_n_kw(1, 0, dest); + if (ret == mp_const_none) { + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } else { + return mp_obj_get_int(ret); + } +} +STATIC mp_uint_t iobase_read(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) { + return iobase_read_write(obj, buf, size, errcode, MP_QSTR_readinto); +} + +STATIC mp_uint_t iobase_write(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode) { + return iobase_read_write(obj, (void*)buf, size, errcode, MP_QSTR_write); +} + +STATIC mp_uint_t iobase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_t dest[4]; + mp_load_method(obj, MP_QSTR_ioctl, dest); + dest[2] = mp_obj_new_int_from_uint(request); + dest[3] = mp_obj_new_int_from_uint(arg); + mp_int_t ret = mp_obj_get_int(mp_call_method_n_kw(2, 0, dest)); + if (ret >= 0) { + return ret; + } else { + *errcode = -ret; + return MP_STREAM_ERROR; + } +} + +STATIC const mp_stream_p_t iobase_p = { + .read = iobase_read, + .write = iobase_write, + .ioctl = iobase_ioctl, +}; + +STATIC const mp_obj_type_t mp_type_iobase = { + { &mp_type_type }, + .name = MP_QSTR_IOBase, + .make_new = iobase_make_new, + .protocol = &iobase_p, +}; + +#endif // MICROPY_PY_IO_IOBASE + #if MICROPY_PY_IO_BUFFEREDWRITER typedef struct _mp_obj_bufwriter_t { mp_obj_base_t base; @@ -131,7 +197,7 @@ STATIC const mp_obj_type_t bufwriter_type = { }; #endif // MICROPY_PY_IO_BUFFEREDWRITER -#if MICROPY_MODULE_FROZEN_STR +#if MICROPY_PY_IO_RESOURCE_STREAM STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX); size_t len; @@ -176,10 +242,10 @@ STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { return MP_OBJ_FROM_PTR(o); } - mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len, false); + mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len); return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map); } -MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); +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[] = { @@ -187,6 +253,9 @@ STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = { // Note: mp_builtin_open_obj should be defined by port, it's not // part of the core. { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + #if MICROPY_PY_IO_IOBASE + { MP_ROM_QSTR(MP_QSTR_IOBase), MP_ROM_PTR(&mp_type_iobase) }, + #endif #if MICROPY_PY_IO_RESOURCE_STREAM { MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) }, #endif diff --git a/py/modmicropython.c b/py/modmicropython.c index 2aac53adc7..864d1a5c5b 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -35,6 +35,7 @@ // Various builtins specific to MicroPython runtime, // living in micropython module +#if MICROPY_ENABLE_COMPILER STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { return MP_OBJ_NEW_SMALL_INT(MP_STATE_VM(mp_optimise_value)); @@ -44,6 +45,7 @@ STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) { } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_opt_level_obj, 0, 1, mp_micropython_opt_level); +#endif #if MICROPY_PY_MICROPYTHON_MEM_INFO @@ -103,14 +105,21 @@ STATIC mp_obj_t mp_micropython_qstr_info(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_qstr_info_obj, 0, 1, mp_micropython_qstr_info); -#if MICROPY_STACK_CHECK +#endif // MICROPY_PY_MICROPYTHON_MEM_INFO + +#if MICROPY_PY_MICROPYTHON_STACK_USE STATIC mp_obj_t mp_micropython_stack_use(void) { return MP_OBJ_NEW_SMALL_INT(mp_stack_usage()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_stack_use_obj, mp_micropython_stack_use); #endif -#endif // MICROPY_PY_MICROPYTHON_MEM_INFO +#if MICROPY_ENABLE_PYSTACK +STATIC mp_obj_t mp_micropython_pystack_use(void) { + return MP_OBJ_NEW_SMALL_INT(mp_pystack_usage()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_pystack_use_obj, mp_micropython_pystack_use); +#endif #if MICROPY_ENABLE_GC STATIC mp_obj_t mp_micropython_heap_lock(void) { @@ -151,7 +160,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_micropython_schedule_obj, mp_micropython_sch STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) }, { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) }, + #if MICROPY_ENABLE_COMPILER { MP_ROM_QSTR(MP_QSTR_opt_level), MP_ROM_PTR(&mp_micropython_opt_level_obj) }, + #endif #if MICROPY_PY_MICROPYTHON_MEM_INFO #if MICROPY_MEM_STATS { MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) }, @@ -160,13 +171,16 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { #endif { MP_ROM_QSTR(MP_QSTR_mem_info), MP_ROM_PTR(&mp_micropython_mem_info_obj) }, { MP_ROM_QSTR(MP_QSTR_qstr_info), MP_ROM_PTR(&mp_micropython_qstr_info_obj) }, - #if MICROPY_STACK_CHECK +#endif + #if MICROPY_PY_MICROPYTHON_STACK_USE { MP_ROM_QSTR(MP_QSTR_stack_use), MP_ROM_PTR(&mp_micropython_stack_use_obj) }, #endif -#endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0) { MP_ROM_QSTR(MP_QSTR_alloc_emergency_exception_buf), MP_ROM_PTR(&mp_alloc_emergency_exception_buf_obj) }, #endif + #if MICROPY_ENABLE_PYSTACK + { MP_ROM_QSTR(MP_QSTR_pystack_use), MP_ROM_PTR(&mp_micropython_pystack_use_obj) }, + #endif #if MICROPY_ENABLE_GC { MP_ROM_QSTR(MP_QSTR_heap_lock), MP_ROM_PTR(&mp_micropython_heap_lock_obj) }, { MP_ROM_QSTR(MP_QSTR_heap_unlock), MP_ROM_PTR(&mp_micropython_heap_unlock_obj) }, diff --git a/py/modsys.c b/py/modsys.c index de3cb7e1ff..e32841923f 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -106,7 +106,8 @@ STATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) { #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES void *stream_obj = &mp_sys_stdout_obj; if (n_args > 1) { - stream_obj = MP_OBJ_TO_PTR(args[1]); // XXX may fail + mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE); + stream_obj = MP_OBJ_TO_PTR(args[1]); } mp_print_t print = {stream_obj, mp_stream_write_adaptor}; @@ -140,10 +141,12 @@ STATIC mp_obj_t mp_sys_exc_info(void) { MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_exc_info_obj, mp_sys_exc_info); #endif +#if MICROPY_PY_SYS_GETSIZEOF STATIC mp_obj_t mp_sys_getsizeof(mp_obj_t obj) { return mp_unary_op(MP_UNARY_OP_SIZEOF, obj); } -MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof); +#endif STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys) }, diff --git a/py/modthread.c b/py/modthread.c index cb071d0f86..61ada50351 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -165,6 +165,12 @@ STATIC void *thread_entry(void *args_in) { mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan mp_stack_set_limit(args->stack_size); + #if MICROPY_ENABLE_PYSTACK + // TODO threading and pystack is not fully supported, for now just make a small stack + mp_obj_t mini_pystack[128]; + mp_pystack_init(mini_pystack, &mini_pystack[128]); + #endif + // set locals and globals from the calling context mp_locals_set(args->dict_locals); mp_globals_set(args->dict_globals); diff --git a/py/mpconfig.h b/py/mpconfig.h index 74d7c2c929..52a7c05a21 100755 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -79,7 +79,7 @@ // - seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 64-bit fp, e != 0x7ff // - s1111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000 +/- inf // - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan -// - 01111111 11111101 00000000 00000000 iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int +// - 01111111 11111101 iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int // - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str // - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment) // Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000. @@ -353,7 +353,7 @@ #endif // Whether to enable optimisation of: a, b, c = d, e, f -// Cost 156 bytes (Thumb2) +// Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2) #ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) #endif @@ -411,6 +411,13 @@ /*****************************************************************************/ /* Python internal features */ +// Whether to enable import of external modules +// When disabled, only importing of built-in modules is supported +// When enabled, a port must implement mp_import_stat (among other things) +#ifndef MICROPY_ENABLE_EXTERNAL_IMPORT +#define MICROPY_ENABLE_EXTERNAL_IMPORT (1) +#endif + // Whether to use the POSIX reader for importing files #ifndef MICROPY_READER_POSIX #define MICROPY_READER_POSIX (0) @@ -452,6 +459,17 @@ #define MICROPY_ENABLE_FINALISER (0) #endif +// Whether to enable a separate allocator for the Python stack. +// If enabled then the code must call mp_pystack_init before mp_init. +#ifndef MICROPY_ENABLE_PYSTACK +#define MICROPY_ENABLE_PYSTACK (0) +#endif + +// Number of bytes that memory returned by mp_pystack_alloc will be aligned by. +#ifndef MICROPY_PYSTACK_ALIGN +#define MICROPY_PYSTACK_ALIGN (8) +#endif + // Whether to check C stack usage. C stack used for calling Python functions, // etc. Not checking means segfault on overflow. #ifndef MICROPY_STACK_CHECK @@ -679,22 +697,41 @@ typedef double mp_float_t; #define MICROPY_VFS (0) #endif +// Support for VFS POSIX component, to mount a POSIX filesystem within VFS +#ifndef MICROPY_VFS +#define MICROPY_VFS_POSIX (0) +#endif + +// Support for VFS FAT component, to mount a FAT filesystem within VFS +#ifndef MICROPY_VFS +#define MICROPY_VFS_FAT (0) +#endif + /*****************************************************************************/ /* Fine control over Python builtins, classes, modules, etc */ +// Whether to support multiple inheritance of Python classes. Multiple +// inheritance makes some C functions inherently recursive, and adds a bit of +// code overhead. +#ifndef MICROPY_MULTIPLE_INHERITANCE +#define MICROPY_MULTIPLE_INHERITANCE (1) +#endif + // Whether to implement attributes on functions #ifndef MICROPY_PY_FUNCTION_ATTRS #define MICROPY_PY_FUNCTION_ATTRS (0) #endif -// Whether to support descriptors (__get__ and __set__) -// This costs some code size and makes all load attrs and store attrs slow +// Whether to support the descriptors __get__, __set__, __delete__ +// This costs some code size and makes load/store/delete of instance +// attributes slower for the classes that use this feature #ifndef MICROPY_PY_DESCRIPTORS #define MICROPY_PY_DESCRIPTORS (0) #endif // Whether to support class __delattr__ and __setattr__ methods -// This costs some code size and makes all del attrs and store attrs slow +// This costs some code size and makes store/delete of instance +// attributes slower for the classes that use this feature #ifndef MICROPY_PY_DELATTR_SETATTR #define MICROPY_PY_DELATTR_SETATTR (0) #endif @@ -704,6 +741,15 @@ typedef double mp_float_t; #define MICROPY_PY_ASYNC_AWAIT (1) #endif +// Non-standard .pend_throw() method for generators, allowing for +// Future-like behavior with respect to exception handling: an +// exception set with .pend_throw() will activate on the next call +// to generator's .send() or .__next__(). (This is useful to implement +// async schedulers.) +#ifndef MICROPY_PY_GENERATOR_PEND_THROW +#define MICROPY_PY_GENERATOR_PEND_THROW (1) +#endif + // Issue a warning when comparing str and bytes objects #ifndef MICROPY_PY_STR_BYTES_CMP_WARN #define MICROPY_PY_STR_BYTES_CMP_WARN (0) @@ -776,6 +822,19 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) #endif +// Whether to support binary ops [only (in)equality is defined] between range +// objects. With this option disabled all range objects that are not exactly +// the same object will compare as not-equal. With it enabled the semantics +// match CPython and ranges are equal if they yield the same sequence of items. +#ifndef MICROPY_PY_BUILTINS_RANGE_BINOP +#define MICROPY_PY_BUILTINS_RANGE_BINOP (0) +#endif + +// Whether to support rounding of integers (incl bignum); eg round(123,-1)=120 +#ifndef MICROPY_PY_BUILTINS_ROUND_INT +#define MICROPY_PY_BUILTINS_ROUND_INT (0) +#endif + // Whether to support timeout exceptions (like socket.timeout) #ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR #define MICROPY_PY_BUILTINS_TIMEOUTERROR (0) @@ -881,6 +940,11 @@ typedef double mp_float_t; #define MICROPY_PY_MICROPYTHON_MEM_INFO (0) #endif +// Whether to provide "micropython.stack_use" function +#ifndef MICROPY_PY_MICROPYTHON_STACK_USE +#define MICROPY_PY_MICROPYTHON_STACK_USE (MICROPY_PY_MICROPYTHON_MEM_INFO) +#endif + // Whether to provide "array" module. Note that large chunk of the // underlying code is shared with "bytearray" builtin type, so to // get real savings, it should be disabled too. @@ -911,11 +975,21 @@ typedef double mp_float_t; #define MICROPY_PY_COLLECTIONS (1) #endif +// Whether to provide "ucollections.deque" type +#ifndef MICROPY_PY_COLLECTIONS_DEQUE +#define MICROPY_PY_COLLECTIONS_DEQUE (0) +#endif + // Whether to provide "collections.OrderedDict" type #ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0) #endif +// Whether to provide the _asdict function for namedtuple +#ifndef MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT +#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (0) +#endif + // Whether to provide "math" module #ifndef MICROPY_PY_MATH #define MICROPY_PY_MATH (1) @@ -946,9 +1020,18 @@ typedef double mp_float_t; #define MICROPY_PY_IO (1) #endif +// Whether to provide "io.IOBase" class to support user streams +#ifndef MICROPY_PY_IO_IOBASE +#define MICROPY_PY_IO_IOBASE (0) +#endif + // Whether to provide "uio.resource_stream()" function with // the semantics of CPython's pkg_resources.resource_stream() -// (allows to access resources in frozen packages). +// (allows to access binary resources in frozen source packages). +// Note that the same functionality can be achieved in "pure +// Python" by prepocessing binary resources into Python source +// and bytecode-freezing it (with a simple helper module available +// e.g. in micropython-lib). #ifndef MICROPY_PY_IO_RESOURCE_STREAM #define MICROPY_PY_IO_RESOURCE_STREAM (0) #endif @@ -1094,6 +1177,14 @@ typedef double mp_float_t; #define MICROPY_PY_UHASHLIB (0) #endif +#ifndef MICROPY_PY_UHASHLIB_SHA1 +#define MICROPY_PY_UHASHLIB_SHA1 (0) +#endif + +#ifndef MICROPY_PY_UHASHLIB_SHA256 +#define MICROPY_PY_UHASHLIB_SHA256 (1) +#endif + #ifndef MICROPY_PY_UBINASCII #define MICROPY_PY_UBINASCII (0) #endif @@ -1217,29 +1308,26 @@ typedef double mp_float_t; #elif defined(MP_ENDIANNESS_BIG) #define MP_ENDIANNESS_LITTLE (!MP_ENDIANNESS_BIG) #else - // Endiannes not defined by port so try to autodetect it. + // Endianness not defined by port so try to autodetect it. #if defined(__BYTE_ORDER__) #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define MP_ENDIANNESS_LITTLE (1) - #else + #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define MP_ENDIANNESS_LITTLE (0) #endif - #elif defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) - #define MP_ENDIANNESS_LITTLE (1) - #elif defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined (_BIG_ENDIAN) - #define MP_ENDIANNESS_LITTLE (0) #else #include #if defined(__BYTE_ORDER) #if __BYTE_ORDER == __LITTLE_ENDIAN #define MP_ENDIANNESS_LITTLE (1) - #else + #elif __BYTE_ORDER == __BIG_ENDIAN #define MP_ENDIANNESS_LITTLE (0) #endif - #else - #error endianness not defined and cannot detect it #endif #endif + #ifndef MP_ENDIANNESS_LITTLE + #error endianness not defined and cannot detect it + #endif #define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE) #endif @@ -1315,4 +1403,24 @@ typedef double mp_float_t; #define MP_UNLIKELY(x) __builtin_expect((x), 0) #endif +#ifndef MP_HTOBE16 +#if MP_ENDIANNESS_LITTLE +# define MP_HTOBE16(x) ((uint16_t)( (((x) & 0xff) << 8) | (((x) >> 8) & 0xff) )) +# define MP_BE16TOH(x) MP_HTOBE16(x) +#else +# define MP_HTOBE16(x) (x) +# define MP_BE16TOH(x) (x) +#endif +#endif + +#ifndef MP_HTOBE32 +#if MP_ENDIANNESS_LITTLE +# define MP_HTOBE32(x) ((uint32_t)( (((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff) )) +# define MP_BE32TOH(x) MP_HTOBE32(x) +#else +# define MP_HTOBE32(x) (x) +# define MP_BE32TOH(x) (x) +#endif +#endif + #endif // MICROPY_INCLUDED_PY_MPCONFIG_H diff --git a/py/mperrno.h b/py/mperrno.h index a028157ba7..1eb342bc36 100644 --- a/py/mperrno.h +++ b/py/mperrno.h @@ -125,7 +125,7 @@ #define MP_EPIPE EPIPE #define MP_EDOM EDOM #define MP_ERANGE ERANGE -#define MP_EWOULDBLOCK EAGAIN +#define MP_EWOULDBLOCK EWOULDBLOCK #define MP_EOPNOTSUPP EOPNOTSUPP #define MP_EAFNOSUPPORT EAFNOSUPPORT #define MP_EADDRINUSE EADDRINUSE diff --git a/py/mpprint.c b/py/mpprint.c index a569ef7931..c2e65301c9 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -446,11 +446,16 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { } } - // parse long specifiers (current not used) - //bool long_arg = false; + // parse long specifiers (only for LP64 model where they make a difference) + #ifndef __LP64__ + const + #endif + bool long_arg = false; if (*fmt == 'l') { ++fmt; - //long_arg = true; + #ifdef __LP64__ + long_arg = true; + #endif } if (*fmt == '\0') { @@ -505,14 +510,21 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { chrs += mp_print_int(print, va_arg(args, int), 1, 10, 'a', flags, fill, width); break; case 'x': - chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'a', flags, fill, width); - break; - case 'X': - chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'A', flags, fill, width); + case 'X': { + char fmt_c = *fmt - 'X' + 'A'; + mp_uint_t val; + if (long_arg) { + val = va_arg(args, unsigned long int); + } else { + val = va_arg(args, unsigned int); + } + chrs += mp_print_int(print, val, 0, 16, fmt_c, flags, fill, width); break; + } case 'p': case 'P': // don't bother to handle upcase for 'P' - chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'a', flags, fill, width); + // Use unsigned long int to work on both ILP32 and LP64 systems + chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width); break; #if MICROPY_PY_BUILTINS_FLOAT case 'e': diff --git a/py/mpstate.h b/py/mpstate.h index c509470662..6e68159eef 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -80,7 +80,6 @@ typedef struct _mp_state_mem_t { int gc_stack_overflow; size_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE]; - size_t *gc_sp; uint16_t gc_lock_depth; // This variable controls auto garbage collection. If set to false then the @@ -109,10 +108,11 @@ typedef struct _mp_state_mem_t { // This structure hold runtime and VM information. It includes a section // which contains root pointers that must be scanned by the GC. typedef struct _mp_state_vm_t { - //////////////////////////////////////////////////////////// - // START ROOT POINTER SECTION - // everything that needs GC scanning must go here - // this must start at the start of this structure + // + // CONTINUE ROOT POINTER SECTION + // This must start at the start of this structure and follows + // the state in the mp_state_thread_t structure, continuing + // the root pointer section from there. // qstr_pool_t *last_pool; @@ -146,8 +146,6 @@ typedef struct _mp_state_vm_t { volatile mp_obj_t mp_pending_exception; #if MICROPY_ENABLE_SCHEDULER - volatile int16_t sched_state; - uint16_t sched_sp; mp_sched_item_t sched_stack[MICROPY_SCHEDULER_DEPTH]; #endif @@ -173,12 +171,15 @@ typedef struct _mp_state_vm_t { // root pointers for extmod - #ifdef MICROPY_PY_OS_DUPTERM - mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM]; - mp_obj_t dupterm_arr_obj; + #if MICROPY_REPL_EVENT_DRIVEN + vstr_t *repl_line; #endif - #ifdef MICROPY_PY_LWIP_SLIP + #if MICROPY_PY_OS_DUPTERM + mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM]; + #endif + + #if MICROPY_PY_LWIP_SLIP mp_obj_t lwip_slip_stream; #endif @@ -202,13 +203,20 @@ typedef struct _mp_state_vm_t { mp_thread_mutex_t qstr_mutex; #endif + #if MICROPY_ENABLE_COMPILER mp_uint_t mp_optimise_value; + #endif // size of the emergency exception buf, if it's dynamically allocated #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0 mp_int_t mp_emergency_exception_buf_size; #endif + #if MICROPY_ENABLE_SCHEDULER + volatile int16_t sched_state; + uint16_t sched_sp; + #endif + #if MICROPY_PY_THREAD_GIL // This is a global mutex used to make the VM/runtime thread-safe. mp_thread_mutex_t gil_mutex; @@ -218,12 +226,6 @@ typedef struct _mp_state_vm_t { // This structure holds state that is specific to a given thread. // Everything in this structure is scanned for root pointers. typedef struct _mp_state_thread_t { - mp_obj_dict_t *dict_locals; - mp_obj_dict_t *dict_globals; - - // Note: nlr asm code has the offset of this hard-coded - nlr_buf_t *nlr_top; // ROOT POINTER - // Stack top at the start of program char *stack_top; @@ -234,12 +236,27 @@ typedef struct _mp_state_thread_t { #if MICROPY_STACK_CHECK size_t stack_limit; #endif + + #if MICROPY_ENABLE_PYSTACK + uint8_t *pystack_start; + uint8_t *pystack_end; + uint8_t *pystack_cur; + #endif + + //////////////////////////////////////////////////////////// + // START ROOT POINTER SECTION + // Everything that needs GC scanning must start here, and + // is followed by state in the mp_state_vm_t structure. + // + + mp_obj_dict_t *dict_locals; + mp_obj_dict_t *dict_globals; + + nlr_buf_t *nlr_top; } mp_state_thread_t; // This structure combines the above 3 structures. // The order of the entries are important for root pointer scanning in the GC to work. -// Note: if this structure changes then revisit all nlr asm code since they -// have the offset of nlr_top hard-coded. typedef struct _mp_state_ctx_t { mp_state_thread_t thread; mp_state_vm_t vm; diff --git a/py/mpz.c b/py/mpz.c index d300a8e5db..8687092d02 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -537,83 +537,57 @@ STATIC void mpn_div(mpz_dig_t *num_dig, size_t *num_len, const mpz_dig_t *den_di // not to overflow the borrow variable. And the shifting of // borrow needs some special logic (it's a shift right with // round up). - - if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) { - const mpz_dig_t *d = den_dig; - mpz_dbl_dig_t d_norm = 0; - mpz_dbl_dig_signed_t borrow = 0; - - for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { - d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); - borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2 - *n = borrow & DIG_MASK; - borrow >>= DIG_SIZE; - } - borrow += *num_dig; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2 - *num_dig = borrow & DIG_MASK; - borrow >>= DIG_SIZE; - - // adjust quotient if it is too big - for (; borrow != 0; --quo) { - d = den_dig; - d_norm = 0; - mpz_dbl_dig_t carry = 0; - for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { - d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); - carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); - *n = carry & DIG_MASK; - carry >>= DIG_SIZE; - } - carry += *num_dig; - *num_dig = carry & DIG_MASK; - carry >>= DIG_SIZE; - - borrow += carry; - } - } else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2 - const mpz_dig_t *d = den_dig; - mpz_dbl_dig_t d_norm = 0; - mpz_dbl_dig_t borrow = 0; - - for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { - d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); - mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); - if (x >= *n || *n - x <= borrow) { - borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n; - *n = (-borrow) & DIG_MASK; - borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up - } else { - *n = ((mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)borrow) & DIG_MASK; - borrow = 0; - } - } - if (borrow >= *num_dig) { - borrow -= (mpz_dbl_dig_t)*num_dig; - *num_dig = (-borrow) & DIG_MASK; + // + const mpz_dig_t *d = den_dig; + mpz_dbl_dig_t d_norm = 0; + mpz_dbl_dig_t borrow = 0; + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); + #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2 + borrow += (mpz_dbl_dig_t)*n - x; // will overflow if DIG_SIZE >= MPZ_DBL_DIG_SIZE/2 + *n = borrow & DIG_MASK; + borrow = (mpz_dbl_dig_signed_t)borrow >> DIG_SIZE; + #else // DIG_SIZE == MPZ_DBL_DIG_SIZE / 2 + if (x >= *n || *n - x <= borrow) { + borrow += x - (mpz_dbl_dig_t)*n; + *n = (-borrow) & DIG_MASK; borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up } else { - *num_dig = (*num_dig - borrow) & DIG_MASK; + *n = ((mpz_dbl_dig_t)*n - x - borrow) & DIG_MASK; borrow = 0; } + #endif + } - // adjust quotient if it is too big - for (; borrow != 0; --quo) { - d = den_dig; - d_norm = 0; - mpz_dbl_dig_t carry = 0; - for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { - d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); - carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); - *n = carry & DIG_MASK; - carry >>= DIG_SIZE; - } - carry += (mpz_dbl_dig_t)*num_dig; - *num_dig = carry & DIG_MASK; + #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2 + // Borrow was negative in the above for-loop, make it positive for next if-block. + borrow = -borrow; + #endif + + // At this point we have either: + // + // 1. quo was the correct value and the most-sig-digit of num is exactly + // cancelled by borrow (borrow == *num_dig). In this case there is + // nothing more to do. + // + // 2. quo was too large, we subtracted too many den from num, and the + // most-sig-digit of num is 1 less than borrow (borrow == *num_dig + 1). + // In this case we must reduce quo and add back den to num until the + // carry from this operation cancels out the borrow. + // + borrow -= *num_dig; + for (; borrow != 0; --quo) { + d = den_dig; + d_norm = 0; + mpz_dbl_dig_t carry = 0; + for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) { + d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE); + carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK); + *n = carry & DIG_MASK; carry >>= DIG_SIZE; - - //assert(borrow >= carry); // enable this to check the logic - borrow -= carry; } + borrow -= carry; } // store this digit of the quotient @@ -731,17 +705,14 @@ STATIC void mpz_need_dig(mpz_t *z, size_t need) { } STATIC mpz_t *mpz_clone(const mpz_t *src) { + assert(src->alloc != 0); mpz_t *z = m_new_obj(mpz_t); z->neg = src->neg; z->fixed_dig = 0; z->alloc = src->alloc; z->len = src->len; - if (src->dig == NULL) { - z->dig = NULL; - } else { - z->dig = m_new(mpz_dig_t, z->alloc); - memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t)); - } + z->dig = m_new(mpz_dig_t, z->alloc); + memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t)); return z; } @@ -1009,6 +980,7 @@ these functions are unused /* returns abs(z) */ mpz_t *mpz_abs(const mpz_t *z) { + // TODO: handle case of z->alloc=0 mpz_t *z2 = mpz_clone(z); z2->neg = 0; return z2; @@ -1017,6 +989,7 @@ mpz_t *mpz_abs(const mpz_t *z) { /* returns -z */ mpz_t *mpz_neg(const mpz_t *z) { + // TODO: handle case of z->alloc=0 mpz_t *z2 = mpz_clone(z); z2->neg = 1 - z2->neg; return z2; @@ -1390,13 +1363,14 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { can have dest, lhs, rhs the same; mod can't be the same as dest */ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) { - if (lhs->len == 0 || rhs->neg != 0) { + if (lhs->len == 0 || rhs->neg != 0 || (mod->len == 1 && mod->dig[0] == 1)) { mpz_set_from_int(dest, 0); return; } + mpz_set_from_int(dest, 1); + if (rhs->len == 0) { - mpz_set_from_int(dest, 1); return; } @@ -1404,8 +1378,6 @@ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t mpz_t *n = mpz_clone(rhs); mpz_t quo; mpz_init_zero(&quo); - mpz_set_from_int(dest, 1); - while (n->len > 0) { if ((n->dig[0] & 1) != 0) { mpz_mul_inpl(dest, dest, x); @@ -1435,6 +1407,7 @@ these functions are unused */ mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) { if (z1->len == 0) { + // TODO: handle case of z2->alloc=0 mpz_t *a = mpz_clone(z2); a->neg = 0; return a; @@ -1559,7 +1532,7 @@ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) { // must return actual int value if it fits in mp_int_t mp_int_t mpz_hash(const mpz_t *z) { - mp_int_t val = 0; + mp_uint_t val = 0; mpz_dig_t *d = z->dig + z->len; while (d-- > z->dig) { @@ -1674,16 +1647,12 @@ char *mpz_as_str(const mpz_t *i, unsigned int base) { } #endif -// assumes enough space as calculated by mp_int_format_size +// assumes enough space in str as calculated by mp_int_format_size +// base must be between 2 and 32 inclusive // returns length of string, not including null byte size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, char base_char, char comma, char *str) { - if (str == NULL) { - return 0; - } - if (base < 2 || base > 32) { - str[0] = 0; - return 0; - } + assert(str != NULL); + assert(2 <= base && base <= 32); size_t ilen = i->len; diff --git a/py/mpz.h b/py/mpz.h index e2d0c30aac..3c36cac66b 100644 --- a/py/mpz.h +++ b/py/mpz.h @@ -55,18 +55,22 @@ #endif #if MPZ_DIG_SIZE > 16 +#define MPZ_DBL_DIG_SIZE (64) typedef uint32_t mpz_dig_t; typedef uint64_t mpz_dbl_dig_t; typedef int64_t mpz_dbl_dig_signed_t; #elif MPZ_DIG_SIZE > 8 +#define MPZ_DBL_DIG_SIZE (32) typedef uint16_t mpz_dig_t; typedef uint32_t mpz_dbl_dig_t; typedef int32_t mpz_dbl_dig_signed_t; #elif MPZ_DIG_SIZE > 4 +#define MPZ_DBL_DIG_SIZE (16) typedef uint8_t mpz_dig_t; typedef uint16_t mpz_dbl_dig_t; typedef int16_t mpz_dbl_dig_signed_t; #else +#define MPZ_DBL_DIG_SIZE (8) typedef uint8_t mpz_dig_t; typedef uint8_t mpz_dbl_dig_t; typedef int8_t mpz_dbl_dig_signed_t; diff --git a/py/nativeglue.c b/py/nativeglue.c index e63c2fcda6..b87da6931e 100644 --- a/py/nativeglue.c +++ b/py/nativeglue.c @@ -146,8 +146,8 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_obj_new_dict, mp_obj_dict_store, #if MICROPY_PY_BUILTINS_SET - mp_obj_new_set, mp_obj_set_store, + mp_obj_new_set, #endif mp_make_function_from_raw_code, mp_native_call_function_n_kw, diff --git a/py/nlr.c b/py/nlr.c new file mode 100644 index 0000000000..03d01577e1 --- /dev/null +++ b/py/nlr.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if !MICROPY_NLR_SETJMP +// When not using setjmp, nlr_push_tail is called from inline asm so needs special care +#if MICROPY_NLR_X86 && MICROPY_NLR_OS_WINDOWS +// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore +unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); +#else +// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as used +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); +#endif +#endif + +unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} diff --git a/py/nlr.h b/py/nlr.h index 8fa6eb950d..90595a12d3 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -30,30 +30,34 @@ // exception handling, basically a stack of setjmp/longjmp buffers #include -#include #include #include "py/mpconfig.h" -typedef struct _nlr_buf_t nlr_buf_t; -struct _nlr_buf_t { - // the entries here must all be machine word size - nlr_buf_t *prev; - void *ret_val; // always a concrete object (an exception instance) -#if !defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP -#define MICROPY_NLR_SETJMP (0) +// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch +#if !MICROPY_NLR_SETJMP +// A lot of nlr-related things need different treatment on Windows +#if defined(_WIN32) || defined(__CYGWIN__) +#define MICROPY_NLR_OS_WINDOWS 1 +#else +#define MICROPY_NLR_OS_WINDOWS 0 +#endif #if defined(__i386__) - void *regs[6]; + #define MICROPY_NLR_X86 (1) + #define MICROPY_NLR_NUM_REGS (6) #elif defined(__x86_64__) - #if defined(__CYGWIN__) - void *regs[12]; - #else - void *regs[8]; - #endif + #define MICROPY_NLR_X64 (1) + #if MICROPY_NLR_OS_WINDOWS + #define MICROPY_NLR_NUM_REGS (10) + #else + #define MICROPY_NLR_NUM_REGS (8) + #endif #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) - void *regs[10]; + #define MICROPY_NLR_THUMB (1) + #define MICROPY_NLR_NUM_REGS (10) #elif defined(__xtensa__) - void *regs[10]; + #define MICROPY_NLR_XTENSA (1) + #define MICROPY_NLR_NUM_REGS (10) #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" @@ -61,24 +65,58 @@ struct _nlr_buf_t { #endif #if MICROPY_NLR_SETJMP - jmp_buf jmpbuf; +#include #endif + +typedef struct _nlr_buf_t nlr_buf_t; +struct _nlr_buf_t { + // the entries here must all be machine word size + nlr_buf_t *prev; + void *ret_val; // always a concrete object (an exception instance) + + #if MICROPY_NLR_SETJMP + jmp_buf jmpbuf; + #else + void *regs[MICROPY_NLR_NUM_REGS]; + #endif + + #if MICROPY_ENABLE_PYSTACK + void *pystack; + #endif }; -#if MICROPY_NLR_SETJMP -#include "py/mpstate.h" +// Helper macros to save/restore the pystack state +#if MICROPY_ENABLE_PYSTACK +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack +#else +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf +#endif -NORETURN void nlr_setjmp_jump(void *val); +// Helper macro to use at the start of a specific nlr_jump implementation +#define MP_NLR_JUMP_HEAD(val, top) \ + nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \ + nlr_buf_t *top = *_top_ptr; \ + if (top == NULL) { \ + nlr_jump_fail(val); \ + } \ + top->ret_val = val; \ + MP_NLR_RESTORE_PYSTACK(top); \ + *_top_ptr = top->prev; \ + +#if MICROPY_NLR_SETJMP // nlr_push() must be defined as a macro, because "The stack context will be // invalidated if the function which called setjmp() returns." -#define nlr_push(buf) ((buf)->prev = MP_STATE_THREAD(nlr_top), MP_STATE_THREAD(nlr_top) = (buf), setjmp((buf)->jmpbuf)) -#define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; } -#define nlr_jump(val) nlr_setjmp_jump(val) +// For this case it is safe to call nlr_push_tail() first. +#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf)) #else unsigned int nlr_push(nlr_buf_t *); +#endif + +unsigned int nlr_push_tail(nlr_buf_t *top); void nlr_pop(void); NORETURN void nlr_jump(void *val); -#endif // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather @@ -107,7 +145,6 @@ NORETURN void nlr_jump_fail(void *val); /* #define nlr_push(val) \ printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_THREAD(nlr_top), val),assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) -#endif */ #endif diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c index 1fb4594403..960dd86f52 100644 --- a/py/nlrsetjmp.c +++ b/py/nlrsetjmp.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,17 +24,18 @@ * THE SOFTWARE. */ -#include "py/nlr.h" +#include "py/mpstate.h" #if MICROPY_NLR_SETJMP -void nlr_setjmp_jump(void *val) { +void nlr_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; if (top == NULL) { nlr_jump_fail(val); } top->ret_val = val; + MP_NLR_RESTORE_PYSTACK(top); *top_ptr = top->prev; longjmp(top->jmpbuf, 1); } diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 0616e59b02..69d3f868af 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) +#if MICROPY_NLR_THUMB #undef nlr_push @@ -82,30 +82,15 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { : "r1", "r2", "r3" // clobbers ); - return 0; // needed to silence compiler warning + #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) + // Older versions of gcc give an error when naked functions don't return a value + // Additionally exclude Clang as it also defines __GNUC__ but doesn't need this statement + return 0; + #endif } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - -NORETURN __attribute__((naked)) void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - *top_ptr = top->prev; +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "mov r0, %0 \n" // r0 points to nlr_buf @@ -142,7 +127,11 @@ NORETURN __attribute__((naked)) void nlr_jump(void *val) { : // clobbered registers ); + #if defined(__GNUC__) + __builtin_unreachable(); + #else for (;;); // needed to silence compiler warning + #endif } -#endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) +#endif // MICROPY_NLR_THUMB diff --git a/py/nlrx64.c b/py/nlrx64.c index 847d10398e..a3a1cf341b 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -26,25 +26,19 @@ #include "py/mpstate.h" -#if !MICROPY_NLR_SETJMP && defined(__x86_64__) +#if MICROPY_NLR_X64 #undef nlr_push // x86-64 callee-save registers are: // rbx, rbp, rsp, r12, r13, r14, r15 -#if defined(_WIN32) || defined(__CYGWIN__) -#define NLR_OS_WINDOWS 1 -#else -#define NLR_OS_WINDOWS 0 -#endif - __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; - #if NLR_OS_WINDOWS + #if MICROPY_NLR_OS_WINDOWS __asm volatile ( "movq (%rsp), %rax \n" // load return %rip @@ -88,31 +82,12 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "movq %0, %%rcx \n" // %rcx points to nlr_buf - #if NLR_OS_WINDOWS + #if MICROPY_NLR_OS_WINDOWS "movq 88(%%rcx), %%rsi \n" // load saved %rsi "movq 80(%%rcx), %%rdi \n" // load saved %rdr #endif @@ -136,4 +111,4 @@ NORETURN void nlr_jump(void *val) { for (;;); // needed to silence compiler warning } -#endif // !MICROPY_NLR_SETJMP && defined(__x86_64__) +#endif // MICROPY_NLR_X64 diff --git a/py/nlrx86.c b/py/nlrx86.c index 094dea3cc8..59b97d8ee6 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -26,34 +26,42 @@ #include "py/mpstate.h" -#if !MICROPY_NLR_SETJMP && defined(__i386__) +#if MICROPY_NLR_X86 #undef nlr_push // For reference, x86 callee save regs are: // ebx, esi, edi, ebp, esp, eip -#if defined(_WIN32) || defined(__CYGWIN__) -#define NLR_OS_WINDOWS 1 -#else -#define NLR_OS_WINDOWS 0 -#endif - -#if NLR_OS_WINDOWS +#if MICROPY_NLR_OS_WINDOWS unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); #else __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); #endif +#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 8 +// Since gcc 8.0 the naked attribute is supported +#define USE_NAKED (1) +#define UNDO_PRELUDE (0) +#elif defined(__ZEPHYR__) || defined(__ANDROID__) +// Zephyr and Android use a different calling convention by default +#define USE_NAKED (0) +#define UNDO_PRELUDE (0) +#else +#define USE_NAKED (0) +#define UNDO_PRELUDE (1) +#endif + +#if USE_NAKED +__attribute__((naked)) +#endif unsigned int nlr_push(nlr_buf_t *nlr) { + #if !USE_NAKED (void)nlr; + #endif __asm volatile ( - // Check for Zephyr, which uses a different calling convention - // by default. - // TODE: Better support for various x86 calling conventions - // (unfortunately, __attribute__((naked)) is not supported on x86). - #if !(defined(__ZEPHYR__) || defined(__ANDROID__)) + #if UNDO_PRELUDE "pop %ebp \n" // undo function's prelude #endif "mov 4(%esp), %edx \n" // load nlr_buf @@ -67,30 +75,13 @@ unsigned int nlr_push(nlr_buf_t *nlr) { "jmp nlr_push_tail \n" // do the rest in C ); + #if !USE_NAKED return 0; // needed to silence compiler warning -} - -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; + #endif } NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "mov %0, %%edx \n" // %edx points to nlr_buf @@ -112,4 +103,4 @@ NORETURN void nlr_jump(void *val) { for (;;); // needed to silence compiler warning } -#endif // !MICROPY_NLR_SETJMP && defined(__i386__) +#endif // MICROPY_NLR_X86 diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index 4520e7e7ac..cd3dee364c 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -26,7 +26,7 @@ #include "py/mpstate.h" -#if !MICROPY_NLR_SETJMP && defined(__xtensa__) +#if MICROPY_NLR_XTENSA #undef nlr_push @@ -55,27 +55,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "mov.n a2, %0 \n" // a2 points to nlr_buf @@ -99,4 +80,4 @@ NORETURN void nlr_jump(void *val) { for (;;); // needed to silence compiler warning } -#endif // !MICROPY_NLR_SETJMP && defined(__xtensa__) +#endif // MICROPY_NLR_XTENSA diff --git a/py/obj.h b/py/obj.h index d086d3c149..42c88ef67f 100644 --- a/py/obj.h +++ b/py/obj.h @@ -172,8 +172,8 @@ static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0001000000000000); } -#define MP_OBJ_SMALL_INT_VALUE(o) (((intptr_t)(o)) >> 1) -#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((uintptr_t)(small_int)) << 1) | 0x0001000000000001) +#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)((o) << 16)) >> 17) +#define MP_OBJ_NEW_SMALL_INT(small_int) (((((uint64_t)(small_int)) & 0x7fffffffffff) << 1) | 0x0001000000000001) static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0002000000000000); } @@ -181,7 +181,7 @@ static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 1) | 0x0002000000000001)) #if MICROPY_PY_BUILTINS_FLOAT -#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b125769 + 0x8004000000000000))} +#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))} #define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))} static inline bool mp_obj_is_float(mp_const_obj_t o) { @@ -252,6 +252,8 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; // The macros below are derived from the ones above and are used to // check for more specific object types. +// Note: these are kept as macros because inline functions sometimes use much +// more code space than the equivalent macros, depending on the compiler. #define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that #define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)) @@ -259,17 +261,6 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; #define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op)) #define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function)) -// Note: inline functions sometimes use much more code space than the -// equivalent macros, depending on the compiler. -//static inline bool MP_OBJ_IS_TYPE(mp_const_obj_t o, const mp_obj_type_t *t) { return (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))); } // this does not work for checking a string, use below macro for that -//static inline bool MP_OBJ_IS_INT(mp_const_obj_t o) { return (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)); } // returns true if o is a small int or long int -// Need to forward declare these for the inline function to compile. -extern const mp_obj_type_t mp_type_int; -extern const mp_obj_type_t mp_type_bool; -static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int -//static inline bool MP_OBJ_IS_STR(mp_const_obj_t o) { return (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)); } - - // These macros are used to declare and define constant function objects // You can put "static" in front of the definitions to make them local @@ -462,22 +453,15 @@ typedef struct _mp_buffer_p_t { bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); -// Stream protocol -typedef struct _mp_stream_p_t { - // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values - // are implementation-dependent, but will be exposed to user, e.g. via exception). - mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); - mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode); - mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); - mp_uint_t is_text : 1; // default is bytes, set this for text stream -} mp_stream_p_t; - struct _mp_obj_type_t { // A type is an object so must start with this entry, which points to mp_type_type. mp_obj_base_t base; - // The name of this type. - qstr name; + // Flags associated with this type. + uint16_t flags; + + // The name of this type, a qstr. + uint16_t name; // Corresponds to __repr__ and __str__ special methods. mp_print_fun_t print; @@ -553,6 +537,7 @@ extern const mp_obj_type_t mp_type_list; extern const mp_obj_type_t mp_type_map; // map (the python builtin, not the dict implementation detail) extern const mp_obj_type_t mp_type_enumerate; extern const mp_obj_type_t mp_type_filter; +extern const mp_obj_type_t mp_type_deque; extern const mp_obj_type_t mp_type_dict; extern const mp_obj_type_t mp_type_ordereddict; extern const mp_obj_type_t mp_type_range; @@ -625,7 +610,6 @@ extern const struct _mp_obj_str_t mp_const_empty_bytes_obj; extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj; extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj; extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj; -extern const struct _mp_obj_exception_t mp_const_MemoryError_obj; extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; // General API for objects @@ -638,7 +622,8 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value); mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base); mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) -mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already); +mp_obj_t mp_obj_new_str(const char* data, size_t len); +mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len); mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr); mp_obj_t mp_obj_new_bytes(const byte* data, size_t len); mp_obj_t mp_obj_new_bytearray(size_t n, void *items); @@ -682,6 +667,7 @@ bool mp_obj_is_true(mp_obj_t arg); bool mp_obj_is_callable(mp_obj_t o_in); bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2); +static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int mp_int_t mp_obj_get_int(mp_const_obj_t arg); mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg); bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value); @@ -729,6 +715,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway conve const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len); mp_obj_t mp_obj_str_intern(mp_obj_t str); +mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj); void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes); #if MICROPY_PY_BUILTINS_FLOAT @@ -753,8 +740,6 @@ void mp_obj_tuple_del(mp_obj_t self_in); mp_int_t mp_obj_tuple_hash(mp_obj_t self_in); // list -struct _mp_obj_list_t; -void mp_obj_list_init(struct _mp_obj_list_t *o, size_t n); mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value); void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); diff --git a/py/objarray.c b/py/objarray.c index c4c547e19f..94f8878577 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -222,7 +222,7 @@ STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args, // test if the object can be written to if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) { - self->typecode |= 0x80; // used to indicate writable buffer + self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer } return MP_OBJ_FROM_PTR(self); @@ -302,8 +302,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs return lhs_in; } - case MP_BINARY_OP_IN: { - /* NOTE `a in b` is `b.__contains__(a)` */ + case MP_BINARY_OP_CONTAINS: { mp_buffer_info_t lhs_bufinfo; mp_buffer_info_t rhs_bufinfo; @@ -448,7 +447,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value uint8_t* dest_items = o->items; #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { - if ((o->typecode & 0x80) == 0) { + if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) { // store to read-only memoryview not allowed return MP_OBJ_NULL; } @@ -507,7 +506,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { index += o->free; - if (value != MP_OBJ_SENTINEL && (o->typecode & 0x80) == 0) { + if (value != MP_OBJ_SENTINEL && !(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) { // store to read-only memoryview return MP_OBJ_NULL; } @@ -533,7 +532,7 @@ STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_ui bufinfo->typecode = o->typecode & TYPECODE_MASK; #if MICROPY_PY_BUILTINS_MEMORYVIEW if (o->base.type == &mp_type_memoryview) { - if ((o->typecode & 0x80) == 0 && (flags & MP_BUFFER_WRITE)) { + if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW) && (flags & MP_BUFFER_WRITE)) { // read-only memoryview return 1; } diff --git a/py/objarray.h b/py/objarray.h index 0389668458..0dad705711 100644 --- a/py/objarray.h +++ b/py/objarray.h @@ -29,6 +29,9 @@ #include "py/obj.h" +// Used only for memoryview types, set in "typecode" to indicate a writable memoryview +#define MP_OBJ_ARRAY_TYPECODE_FLAG_RW (0x80) + typedef struct _mp_obj_array_t { mp_obj_base_t base; size_t typecode : 8; diff --git a/py/objboundmeth.c b/py/objboundmeth.c index 890f8b15b6..b0df6a68a7 100644 --- a/py/objboundmeth.c +++ b/py/objboundmeth.c @@ -51,6 +51,9 @@ mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, s // need to insert self before all other args and then call meth size_t n_total = n_args + 2 * n_kw; mp_obj_t *args2 = NULL; + #if MICROPY_ENABLE_PYSTACK + args2 = mp_pystack_alloc(sizeof(mp_obj_t) * (1 + n_total)); + #else mp_obj_t *free_args2 = NULL; if (n_total > 4) { // try to use heap to allocate temporary args array @@ -61,12 +64,17 @@ mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, s // (fallback to) use stack to allocate temporary args array args2 = alloca(sizeof(mp_obj_t) * (1 + n_total)); } + #endif args2[0] = self; memcpy(args2 + 1, args, n_total * sizeof(mp_obj_t)); mp_obj_t res = mp_call_function_n_kw(meth, n_args + 1, n_kw, args2); + #if MICROPY_ENABLE_PYSTACK + mp_pystack_free(args2); + #else if (free_args2 != NULL) { m_del(mp_obj_t, free_args2, 1 + n_total); } + #endif return res; } diff --git a/py/objdeque.c b/py/objdeque.c new file mode 100644 index 0000000000..1cff1f8d3b --- /dev/null +++ b/py/objdeque.c @@ -0,0 +1,167 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include // for ssize_t +#include + +#include "py/mpconfig.h" +#if MICROPY_PY_COLLECTIONS_DEQUE + +#include "py/runtime.h" + +typedef struct _mp_obj_deque_t { + mp_obj_base_t base; + size_t alloc; + size_t i_get; + size_t i_put; + mp_obj_t *items; + uint32_t flags; + #define FLAG_CHECK_OVERFLOW 1 +} mp_obj_deque_t; + +STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 3, false); + + /* Initialization from existing sequence is not supported, so an empty + tuple must be passed as such. */ + if (args[0] != mp_const_empty_tuple) { + mp_raise_ValueError(NULL); + } + + // Protect against -1 leading to zero-length allocation and bad array access + mp_int_t maxlen = mp_obj_get_int(args[1]); + if (maxlen < 0) { + mp_raise_ValueError(NULL); + } + + mp_obj_deque_t *o = m_new_obj(mp_obj_deque_t); + o->base.type = type; + o->alloc = maxlen + 1; + o->i_get = o->i_put = 0; + o->items = m_new0(mp_obj_t, o->alloc); + + if (n_args > 2) { + o->flags = mp_obj_get_int(args[2]); + } + + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: + return mp_obj_new_bool(self->i_get != self->i_put); + case MP_UNARY_OP_LEN: { + ssize_t len = self->i_put - self->i_get; + if (len < 0) { + len += self->alloc; + } + return MP_OBJ_NEW_SMALL_INT(len); + } + #if MICROPY_PY_SYS_GETSIZEOF + case MP_UNARY_OP_SIZEOF: { + size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc; + return MP_OBJ_NEW_SMALL_INT(sz); + } + #endif + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + + size_t new_i_put = self->i_put + 1; + if (new_i_put == self->alloc) { + new_i_put = 0; + } + + if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) { + mp_raise_msg(&mp_type_IndexError, "full"); + } + + self->items[self->i_put] = arg; + self->i_put = new_i_put; + + if (self->i_get == new_i_put) { + if (++self->i_get == self->alloc) { + self->i_get = 0; + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append); + +STATIC mp_obj_t deque_popleft(mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->i_get == self->i_put) { + mp_raise_msg(&mp_type_IndexError, "empty"); + } + + mp_obj_t ret = self->items[self->i_get]; + self->items[self->i_get] = MP_OBJ_NULL; + + if (++self->i_get == self->alloc) { + self->i_get = 0; + } + + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft); + +#if 0 +STATIC mp_obj_t deque_clear(mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + self->i_get = self->i_put = 0; + mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear); +#endif + +STATIC const mp_rom_map_elem_t deque_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&deque_append_obj) }, + #if 0 + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&deque_clear_obj) }, + #endif + { MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&deque_popleft_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table); + +const mp_obj_type_t mp_type_deque = { + { &mp_type_type }, + .name = MP_QSTR_deque, + .make_new = deque_make_new, + .unary_op = deque_unary_op, + .locals_dict = (mp_obj_dict_t*)&deque_locals_dict, +}; + +#endif // MICROPY_PY_COLLECTIONS_DEQUE diff --git a/py/objdict.c b/py/objdict.c index 1553a83b46..c0647067a1 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -115,7 +115,7 @@ STATIC mp_obj_t dict_unary_op(mp_unary_op_t op, mp_obj_t self_in) { STATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_dict_t *o = MP_OBJ_TO_PTR(lhs_in); switch (op) { - case MP_BINARY_OP_IN: { + case MP_BINARY_OP_CONTAINS: { mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP); return mp_obj_new_bool(elem != NULL); } @@ -193,42 +193,18 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } /******************************************************************************/ -/* dict iterator */ +/* dict methods */ -typedef struct _mp_obj_dict_it_t { - mp_obj_base_t base; - mp_fun_1_t iternext; - mp_obj_t dict; - size_t cur; -} mp_obj_dict_it_t; - -STATIC mp_obj_t dict_it_iternext(mp_obj_t self_in) { - mp_obj_dict_it_t *self = MP_OBJ_TO_PTR(self_in); - mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur); - - if (next == NULL) { - return MP_OBJ_STOP_ITERATION; - } else { - return next->key; +STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) { + if (dict->map.is_fixed) { + mp_raise_TypeError(NULL); } } -STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { - assert(sizeof(mp_obj_dict_it_t) <= sizeof(mp_obj_iter_buf_t)); - mp_obj_dict_it_t *o = (mp_obj_dict_it_t*)iter_buf; - o->base.type = &mp_type_polymorph_iter; - o->iternext = dict_it_iternext; - o->dict = self_in; - o->cur = 0; - return MP_OBJ_FROM_PTR(o); -} - -/******************************************************************************/ -/* dict methods */ - STATIC mp_obj_t dict_clear(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); mp_map_clear(&self->map); @@ -284,6 +260,9 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromk STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) { mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); + if (lookup_kind != MP_MAP_LOOKUP) { + mp_ensure_not_fixed(self); + } mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind); mp_obj_t value; if (elem == NULL || elem->value == MP_OBJ_NULL) { @@ -326,6 +305,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setde STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); size_t cur = 0; mp_map_elem_t *next = dict_iter_next(self, &cur); if (next == NULL) { @@ -344,6 +324,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem); STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); + mp_ensure_not_fixed(self); mp_arg_check_num(n_args, kwargs->used, 1, 2, true); @@ -485,7 +466,7 @@ STATIC mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t if (o->kind != MP_DICT_VIEW_KEYS) { return MP_OBJ_NULL; // op not supported } - if (op != MP_BINARY_OP_IN) { + if (op != MP_BINARY_OP_CONTAINS) { return MP_OBJ_NULL; // op not supported } return dict_binary_op(op, o->dict, rhs_in); @@ -527,6 +508,20 @@ STATIC mp_obj_t dict_values(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values); +/******************************************************************************/ +/* dict iterator */ + +STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t*)iter_buf; + o->base.type = &dict_view_it_type; + o->kind = MP_DICT_VIEW_KEYS; + o->dict = self_in; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} + /******************************************************************************/ /* dict constructors & public C API */ @@ -595,6 +590,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) { mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; return self_in; } diff --git a/py/objexcept.c b/py/objexcept.c index f0874df773..5b5650c5f4 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -43,9 +43,6 @@ // Number of traceback entries to reserve in the emergency exception buffer #define EMG_TRACEBACK_ALLOC (2 * TRACEBACK_ENTRY_LEN) -// Instance of MemoryError exception - needed by mp_malloc_fail -const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; - // Optionally allocated buffer for storing the first argument of an exception // allocated when the heap is locked. #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF @@ -96,7 +93,7 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) { // definition module-private so far, have it here. const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj}; -STATIC void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { +void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_exception_t *o = MP_OBJ_TO_PTR(o_in); mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; bool is_subclass = kind & PRINT_EXC_SUBCLASS; @@ -117,7 +114,7 @@ STATIC void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_pr if (o->base.type == &mp_type_OSError && MP_OBJ_IS_SMALL_INT(o->args->items[0])) { qstr qst = mp_errno_to_str(o->args->items[0]); if (qst != MP_QSTR_NULL) { - mp_printf(print, "[Errno %d] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); + mp_printf(print, "[Errno " INT_FMT "] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); return; } } @@ -187,7 +184,7 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) { } } -STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] != MP_OBJ_NULL) { // store/delete attribute @@ -210,37 +207,12 @@ STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } } -STATIC mp_obj_t exc___init__(size_t n_args, const mp_obj_t *args) { - mp_obj_exception_t *self = MP_OBJ_TO_PTR(args[0]); - mp_obj_t argst = mp_obj_new_tuple(n_args - 1, args + 1); - self->args = MP_OBJ_TO_PTR(argst); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(exc___init___obj, 1, MP_OBJ_FUN_ARGS_MAX, exc___init__); - -STATIC const mp_rom_map_elem_t exc_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&exc___init___obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(exc_locals_dict, exc_locals_dict_table); - const mp_obj_type_t mp_type_BaseException = { { &mp_type_type }, .name = MP_QSTR_BaseException, .print = mp_obj_exception_print, .make_new = mp_obj_exception_make_new, - .attr = exception_attr, - .locals_dict = (mp_obj_dict_t*)&exc_locals_dict, -}; - -#define MP_DEFINE_EXCEPTION(exc_name, base_name) \ -const mp_obj_type_t mp_type_ ## exc_name = { \ - { &mp_type_type }, \ - .name = MP_QSTR_ ## exc_name, \ - .print = mp_obj_exception_print, \ - .make_new = mp_obj_exception_make_new, \ - .attr = exception_attr, \ - .parent = &mp_type_ ## base_name, \ + .attr = mp_obj_exception_attr, }; // List of all exceptions, arranged as in the table at: diff --git a/py/objexcept.h b/py/objexcept.h index f67651a7eb..7c30762248 100644 --- a/py/objexcept.h +++ b/py/objexcept.h @@ -37,4 +37,17 @@ typedef struct _mp_obj_exception_t { mp_obj_tuple_t *args; } mp_obj_exception_t; +void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); +void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); + +#define MP_DEFINE_EXCEPTION(exc_name, base_name) \ +const mp_obj_type_t mp_type_ ## exc_name = { \ + { &mp_type_type }, \ + .name = MP_QSTR_ ## exc_name, \ + .print = mp_obj_exception_print, \ + .make_new = mp_obj_exception_make_new, \ + .attr = mp_obj_exception_attr, \ + .parent = &mp_type_ ## base_name, \ +}; + #endif // MICROPY_INCLUDED_PY_OBJEXCEPT_H diff --git a/py/objfloat.c b/py/objfloat.c index fde2224ad4..16aa9bc201 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -91,7 +91,7 @@ typedef uint32_t mp_float_uint_t; if (adj_exp <= MP_FLOAT_FRAC_BITS) { // number may have a fraction; xor the integer part with the fractional part val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp)) - ^ (frc & ((1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1)); + ^ (frc & (((mp_float_uint_t)1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1)); } else if ((unsigned int)adj_exp < BITS_PER_BYTE * sizeof(mp_int_t) - 1) { // the number is a (big) whole integer and will fit in val's signed-width val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS); @@ -102,7 +102,7 @@ typedef uint32_t mp_float_uint_t; } if (u.p.sgn) { - val = -val; + val = -(mp_uint_t)val; } return val; @@ -140,12 +140,11 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size return mp_obj_new_float(0); case 1: - default: - if (MP_OBJ_IS_STR(args[0])) { - // a string, parse it - size_t l; - const char *s = mp_obj_str_get_data(args[0], &l); - return mp_parse_num_decimal(s, l, false, false, NULL); + default: { + mp_buffer_info_t bufinfo; + if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) { + // a textual representation, parse it + return mp_parse_num_decimal(bufinfo.buf, bufinfo.len, false, false, NULL); } else if (mp_obj_is_float(args[0])) { // a float, just return it return args[0]; @@ -153,6 +152,7 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size // something else, try to cast it to a float return mp_obj_new_float(mp_obj_get_float(args[0])); } + } } } @@ -296,7 +296,7 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t break; case MP_BINARY_OP_POWER: case MP_BINARY_OP_INPLACE_POWER: - if (lhs_val == 0 && rhs_val < 0) { + if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) { goto zero_division_error; } if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val)) { diff --git a/py/objfun.c b/py/objfun.c index 030b3f7cb0..8c51d92e06 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -195,32 +195,54 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { // than this will try to use the heap, with fallback to stack allocation. #define VM_MAX_STATE_ON_STACK (11 * sizeof(mp_uint_t)) -// Set this to enable a simple stack overflow check. +// Set this to 1 to enable a simple stack overflow check. #define VM_DETECT_STACK_OVERFLOW (0) +#define DECODE_CODESTATE_SIZE(bytecode, n_state_out_var, state_size_out_var) \ + { \ + /* bytecode prelude: state size and exception stack size */ \ + n_state_out_var = mp_decode_uint_value(bytecode); \ + size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(bytecode)); \ + \ + n_state_out_var += VM_DETECT_STACK_OVERFLOW; \ + \ + /* state size in bytes */ \ + state_size_out_var = n_state_out_var * sizeof(mp_obj_t) \ + + n_exc_stack * sizeof(mp_exc_stack_t); \ + } + +#define INIT_CODESTATE(code_state, _fun_bc, n_args, n_kw, args) \ + code_state->fun_bc = _fun_bc; \ + code_state->ip = 0; \ + mp_setup_code_state(code_state, n_args, n_kw, args); \ + code_state->old_globals = mp_globals_get(); + #if MICROPY_STACKLESS mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); - // bytecode prelude: state size and exception stack size - size_t n_state = mp_decode_uint_value(self->bytecode); - size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode)); + size_t n_state, state_size; + DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size); - // allocate state for locals and stack - size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state_t *code_state; + #if MICROPY_ENABLE_PYSTACK + code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size); + #else + // If we use m_new_obj_var(), then on no memory, MemoryError will be + // raised. But this is not correct exception for a function call, + // RuntimeError should be raised instead. So, we use m_new_obj_var_maybe(), + // return NULL, then vm.c takes the needed action (either raise + // RuntimeError or fallback to stack allocation). code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); if (!code_state) { return NULL; } + #endif - code_state->fun_bc = self; - code_state->ip = 0; - mp_setup_code_state(code_state, n_args, n_kw, args); + INIT_CODESTATE(code_state, self, n_args, n_kw, args); // execute the byte code with the correct globals context - code_state->old_globals = mp_globals_get(); mp_globals_set(self->globals); return code_state; @@ -238,17 +260,14 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); DEBUG_printf("Func n_def_args: %d\n", self->n_def_args); - // bytecode prelude: state size and exception stack size - size_t n_state = mp_decode_uint_value(self->bytecode); - size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode)); - -#if VM_DETECT_STACK_OVERFLOW - n_state += 1; -#endif + size_t n_state, state_size; + DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size); // allocate state for locals and stack - size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); mp_code_state_t *code_state = NULL; + #if MICROPY_ENABLE_PYSTACK + code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size); + #else if (state_size > VM_MAX_STATE_ON_STACK) { code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); } @@ -256,13 +275,11 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const code_state = alloca(sizeof(mp_code_state_t) + state_size); state_size = 0; // indicate that we allocated using alloca } + #endif - code_state->fun_bc = self; - code_state->ip = 0; - mp_setup_code_state(code_state, n_args, n_kw, args); + INIT_CODESTATE(code_state, self, n_args, n_kw, args); // execute the byte code with the correct globals context - code_state->old_globals = mp_globals_get(); mp_globals_set(self->globals); mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL); mp_globals_set(code_state->old_globals); @@ -304,10 +321,14 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const result = code_state->state[n_state - 1]; } + #if MICROPY_ENABLE_PYSTACK + mp_pystack_free(code_state); + #else // free the state if it was allocated on the heap if (state_size != 0) { m_del_var(mp_code_state_t, byte, state_size, code_state); } + #endif if (vm_return_kind == MP_VM_RETURN_NORMAL) { return result; diff --git a/py/objgenerator.c b/py/objgenerator.c index ff566c0768..5664052f53 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -4,7 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -106,12 +106,31 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ mp_raise_TypeError("can't send non-None value to a just-started generator"); } } else { - *self->code_state.sp = send_value; + #if MICROPY_PY_GENERATOR_PEND_THROW + // If exception is pending (set using .pend_throw()), process it now. + if (*self->code_state.sp != mp_const_none) { + throw_value = *self->code_state.sp; + *self->code_state.sp = MP_OBJ_NULL; + } else + #endif + { + *self->code_state.sp = send_value; + } } - mp_obj_dict_t *old_globals = mp_globals_get(); + + // We set self->globals=NULL while executing, for a sentinel to ensure the generator + // cannot be reentered during execution + if (self->globals == NULL) { + mp_raise_ValueError("generator already executing"); + } + + // Set up the correct globals context for the generator and execute it + self->code_state.old_globals = mp_globals_get(); mp_globals_set(self->globals); + self->globals = NULL; mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value); - mp_globals_set(old_globals); + self->globals = mp_globals_get(); + mp_globals_set(self->code_state.old_globals); switch (ret_kind) { case MP_VM_RETURN_NORMAL: @@ -127,9 +146,9 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ case MP_VM_RETURN_YIELD: *ret_val = *self->code_state.sp; - if (*ret_val == MP_OBJ_STOP_ITERATION) { - self->code_state.ip = 0; - } + #if MICROPY_PY_GENERATOR_PEND_THROW + *self->code_state.sp = mp_const_none; + #endif break; case MP_VM_RETURN_EXCEPTION: { @@ -224,10 +243,24 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close); +STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) { + mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); + if (self->code_state.sp == self->code_state.state - 1) { + mp_raise_TypeError("can't pend throw to just-started generator"); + } + mp_obj_t prev = *self->code_state.sp; + *self->code_state.sp = exc_in; + return prev; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_pend_throw_obj, gen_instance_pend_throw); + STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&gen_instance_send_obj) }, { MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&gen_instance_throw_obj) }, + #if MICROPY_PY_GENERATOR_PEND_THROW + { MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table); diff --git a/py/objint.c b/py/objint.c index 4f2e610a50..270e169694 100644 --- a/py/objint.c +++ b/py/objint.c @@ -222,27 +222,26 @@ size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char co char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma) { fmt_int_t num; + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE + // Only have small ints; get the integer value to format. + num = MP_OBJ_SMALL_INT_VALUE(self_in); + #else if (MP_OBJ_IS_SMALL_INT(self_in)) { // A small int; get the integer value to format. num = MP_OBJ_SMALL_INT_VALUE(self_in); -#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) { + } else { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); // Not a small int. -#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG const mp_obj_int_t *self = self_in; // Get the value to format; mp_obj_get_int truncates to mp_int_t. num = self->val; -#else + #else // Delegate to the implementation for the long int. return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma); -#endif -#endif - } else { - // Not an int. - **buf = '\0'; - *fmt_size = 0; - return *buf; + #endif } + #endif char sign = '\0'; if (num < 0) { @@ -378,7 +377,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp // true acts as 0 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1)); } else if (op == MP_BINARY_OP_MULTIPLY) { - if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_bytes) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { + if (MP_OBJ_IS_STR_OR_BYTES(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { // multiply is commutative for these types, so delegate to them return mp_binary_op(op, rhs_in, lhs_in); } diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 2e567c5721..cb8d1672d9 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -124,10 +124,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i if (MP_OBJ_IS_SMALL_INT(lhs_in)) { lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); - } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) { - lhs_val = ((mp_obj_int_t*)lhs_in)->val; } else { - return MP_OBJ_NULL; // op not supported + assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + lhs_val = ((mp_obj_int_t*)lhs_in)->val; } if (MP_OBJ_IS_SMALL_INT(rhs_in)) { @@ -151,9 +150,15 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return mp_obj_new_int_from_ll(lhs_val * rhs_val); case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: + if (rhs_val == 0) { + goto zero_division; + } return mp_obj_new_int_from_ll(lhs_val / rhs_val); case MP_BINARY_OP_MODULO: case MP_BINARY_OP_INPLACE_MODULO: + if (rhs_val == 0) { + goto zero_division; + } return mp_obj_new_int_from_ll(lhs_val % rhs_val); case MP_BINARY_OP_AND: @@ -210,6 +215,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i default: return MP_OBJ_NULL; // op not supported } + +zero_division: + mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } mp_obj_t mp_obj_new_int(mp_int_t value) { diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 808fae6e41..6ee1286408 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -170,11 +170,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i if (MP_OBJ_IS_SMALL_INT(lhs_in)) { mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in)); zlhs = &z_int; - } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) { - zlhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in))->mpz; } else { - // unsupported type - return MP_OBJ_NULL; + assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)); + zlhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in))->mpz; } // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it) @@ -207,7 +205,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return mp_obj_new_float(flhs / frhs); #endif - } else if (op >= MP_BINARY_OP_INPLACE_OR) { + } else if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) { mp_obj_int_t *res = mp_obj_int_new_mpz(); switch (op) { diff --git a/py/objlist.h b/py/objlist.h index 28b5495a92..a43663db76 100644 --- a/py/objlist.h +++ b/py/objlist.h @@ -35,4 +35,6 @@ typedef struct _mp_obj_list_t { mp_obj_t *items; } mp_obj_list_t; +void mp_obj_list_init(mp_obj_list_t *o, size_t n); + #endif // MICROPY_INCLUDED_PY_OBJLIST_H diff --git a/py/objmodule.c b/py/objmodule.c index e3464ecfa8..b28fb2416c 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -259,17 +259,7 @@ mp_obj_t mp_module_get(qstr module_name) { if (el == NULL) { return MP_OBJ_NULL; } - - if (MICROPY_MODULE_BUILTIN_INIT) { - // look for __init__ and call it if it exists - mp_obj_t dest[2]; - mp_load_method_maybe(el->value, MP_QSTR___init__, dest); - if (dest[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, dest); - // register module so __init__ is not called again - mp_module_register(module_name, el->value); - } - } + mp_module_call_init(module_name, el->value); } // module found, return it @@ -280,3 +270,19 @@ void mp_module_register(qstr qst, mp_obj_t module) { mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; } + +#if MICROPY_MODULE_BUILTIN_INIT +void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { + // Look for __init__ and call it if it exists + mp_obj_t dest[2]; + mp_load_method_maybe(module_obj, MP_QSTR___init__, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, dest); + // Register module so __init__ is not called again. + // If a module can be referenced by more than one name (eg due to weak links) + // then __init__ will still be called for each distinct import, and it's then + // up to the particular module to make sure it's __init__ code only runs once. + mp_module_register(module_name, module_obj); + } +} +#endif diff --git a/py/objmodule.h b/py/objmodule.h index b5c07dc333..b7702ec50b 100644 --- a/py/objmodule.h +++ b/py/objmodule.h @@ -34,4 +34,13 @@ extern const mp_map_t mp_builtin_module_weak_links_map; mp_obj_t mp_module_get(qstr module_name); void mp_module_register(qstr qstr, mp_obj_t module); +#if MICROPY_MODULE_BUILTIN_INIT +void mp_module_call_init(qstr module_name, mp_obj_t module_obj); +#else +static inline void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { + (void)module_name; + (void)module_obj; +} +#endif + #endif // MICROPY_INCLUDED_PY_OBJMODULE_H diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 2288fa7b67..832a4a6717 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -27,15 +27,14 @@ #include -#include "py/nlr.h" -#include "py/objnamedtuple.h" #include "py/objtuple.h" #include "py/runtime.h" #include "py/objstr.h" +#include "py/objnamedtuple.h" #if MICROPY_PY_COLLECTIONS -STATIC size_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) { +size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) { for (size_t i = 0; i < type->n_fields; i++) { if (type->fields[i] == name) { return i; @@ -44,7 +43,24 @@ STATIC size_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr n return (size_t)-1; } -void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { +#if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT +STATIC mp_obj_t namedtuple_asdict(mp_obj_t self_in) { + mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in); + const qstr *fields = ((mp_obj_namedtuple_type_t*)self->tuple.base.type)->fields; + mp_obj_t dict = mp_obj_new_dict(self->tuple.len); + //make it an OrderedDict + mp_obj_dict_t *dictObj = MP_OBJ_TO_PTR(dict); + dictObj->base.type = &mp_type_ordereddict; + dictObj->map.is_ordered = 1; + for (size_t i = 0; i < self->tuple.len; ++i) { + mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(fields[i]), self->tuple.items[i]); + } + return dict; +} +MP_DEFINE_CONST_FUN_OBJ_1(namedtuple_asdict_obj, namedtuple_asdict); +#endif + +STATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_namedtuple_t *o = MP_OBJ_TO_PTR(o_in); mp_printf(print, "%q", o->tuple.base.type->name); @@ -52,11 +68,18 @@ void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t ki mp_obj_attrtuple_print_helper(print, fields, &o->tuple); } -void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { // load attribute mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in); - size_t id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); + #if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT + if (attr == MP_QSTR__asdict) { + dest[0] = MP_OBJ_FROM_PTR(&namedtuple_asdict_obj); + dest[1] = self_in; + return; + } + #endif + size_t id = mp_obj_namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); if (id == (size_t)-1) { return; } @@ -96,7 +119,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t memset(&tuple->items[n_args], 0, sizeof(mp_obj_t) * n_kw); for (size_t i = n_args; i < n_args + 2 * n_kw; i += 2) { qstr kw = mp_obj_str_get_qstr(args[i]); - size_t id = namedtuple_find_field(type, kw); + size_t id = mp_obj_namedtuple_find_field(type, kw); if (id == (size_t)-1) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); @@ -119,9 +142,18 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t return MP_OBJ_FROM_PTR(tuple); } -STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) { +mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields) { mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields); memset(&o->base, 0, sizeof(o->base)); + o->n_fields = n_fields; + for (size_t i = 0; i < n_fields; i++) { + o->fields[i] = mp_obj_str_get_qstr(fields[i]); + } + return o; +} + +STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) { + mp_obj_namedtuple_type_t *o = mp_obj_new_namedtuple_base(n_fields, fields); o->base.base.type = &mp_type_type; o->base.name = name; o->base.print = namedtuple_print; @@ -132,10 +164,6 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t o->base.subscr = mp_obj_tuple_subscr; o->base.getiter = mp_obj_tuple_getiter; o->base.parent = &mp_type_tuple; - o->n_fields = n_fields; - for (size_t i = 0; i < n_fields; i++) { - o->fields[i] = mp_obj_str_get_qstr(fields[i]); - } return MP_OBJ_FROM_PTR(o); } diff --git a/py/objnamedtuple.h b/py/objnamedtuple.h index a36404b8d4..d32af35afe 100644 --- a/py/objnamedtuple.h +++ b/py/objnamedtuple.h @@ -1,10 +1,9 @@ /* - * This file is part of the Micro Python project, http://micropython.org/ + * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,22 +23,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - #ifndef MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H #define MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H -#include - -#include "py/nlr.h" #include "py/objtuple.h" -#include "py/runtime.h" -#include "py/objstr.h" - -#if MICROPY_PY_COLLECTIONS typedef struct _mp_obj_namedtuple_type_t { mp_obj_type_t base; - mp_uint_t n_fields; + size_t n_fields; qstr fields[]; } mp_obj_namedtuple_type_t; @@ -47,12 +38,7 @@ typedef struct _mp_obj_namedtuple_t { mp_obj_tuple_t tuple; } mp_obj_namedtuple_t; -void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); +size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name); +mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields); -void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); - -mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args); - -#endif // MICROPY_PY_COLLECTIONS - -#endif // MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H +#endif // MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H diff --git a/py/objobject.c b/py/objobject.c index 49d2ec62ee..265fcfbf2b 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -52,9 +52,12 @@ STATIC mp_obj_t object___new__(mp_obj_t cls) { if (!MP_OBJ_IS_TYPE(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) { mp_raise_TypeError("__new__ arg must be a user-type"); } - mp_obj_t o = MP_OBJ_SENTINEL; - mp_obj_t res = mp_obj_instance_make_new(MP_OBJ_TO_PTR(cls), 1, 0, &o); - return res; + // This executes only "__new__" part of instance creation. + // TODO: This won't work well for classes with native bases. + // TODO: This is a hack, should be resolved along the lines of + // https://github.com/micropython/micropython/issues/606#issuecomment-43685883 + const mp_obj_type_t *native_base; + return MP_OBJ_FROM_PTR(mp_obj_new_instance(MP_OBJ_TO_PTR(cls), &native_base)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__); STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, MP_ROM_PTR(&object___new___fun_obj)); diff --git a/py/objrange.c b/py/objrange.c index 3874adb11c..86aa0ccfe6 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -138,6 +138,24 @@ STATIC mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } } +#if MICROPY_PY_BUILTINS_RANGE_BINOP +STATIC mp_obj_t range_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + if (!MP_OBJ_IS_TYPE(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) { + return MP_OBJ_NULL; // op not supported + } + mp_obj_range_t *lhs = MP_OBJ_TO_PTR(lhs_in); + mp_obj_range_t *rhs = MP_OBJ_TO_PTR(rhs_in); + mp_int_t lhs_len = range_len(lhs); + mp_int_t rhs_len = range_len(rhs); + return mp_obj_new_bool( + lhs_len == rhs_len + && (lhs_len == 0 + || (lhs->start == rhs->start + && (lhs_len == 1 || lhs->step == rhs->step))) + ); +} +#endif + STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_SENTINEL) { // load @@ -195,6 +213,9 @@ const mp_obj_type_t mp_type_range = { .print = range_print, .make_new = range_make_new, .unary_op = range_unary_op, + #if MICROPY_PY_BUILTINS_RANGE_BINOP + .binary_op = range_binary_op, + #endif .subscr = range_subscr, .getiter = range_getiter, #if MICROPY_PY_BUILTINS_RANGE_ATTRS diff --git a/py/objset.c b/py/objset.c index 6ed15c7914..799ba9df04 100644 --- a/py/objset.c +++ b/py/objset.c @@ -351,11 +351,9 @@ STATIC mp_obj_t set_issuperset_proper(mp_obj_t self_in, mp_obj_t other_in) { } STATIC mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) { + assert(is_set_or_frozenset(other_in)); check_set_or_frozenset(self_in); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); - if (!is_set_or_frozenset(other_in)) { - return mp_const_false; - } mp_obj_set_t *other = MP_OBJ_TO_PTR(other_in); if (self->set.used != other->set.used) { return mp_const_false; @@ -461,7 +459,7 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { #else bool update = true; #endif - if (op != MP_BINARY_OP_IN && !is_set_or_frozenset(rhs)) { + if (op != MP_BINARY_OP_CONTAINS && !is_set_or_frozenset(rhs)) { // For all ops except containment the RHS must be a set/frozenset return MP_OBJ_NULL; } @@ -507,7 +505,7 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { return set_issubset(lhs, rhs); case MP_BINARY_OP_MORE_EQUAL: return set_issuperset(lhs, rhs); - case MP_BINARY_OP_IN: { + case MP_BINARY_OP_CONTAINS: { mp_obj_set_t *o = MP_OBJ_TO_PTR(lhs); mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP); return mp_obj_new_bool(elem != MP_OBJ_NULL); diff --git a/py/objstr.c b/py/objstr.c index 7ace1cf739..aae5301ec4 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -164,7 +164,14 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ mp_raise_msg(&mp_type_UnicodeError, NULL); } #endif - mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(type, NULL, str_len)); + + // Check if a qstr with this data already exists + qstr q = qstr_find_strn((const char*)str_data, str_len); + if (q != MP_QSTR_NULL) { + return MP_OBJ_NEW_QSTR(q); + } + + mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len)); o->data = str_data; o->hash = str_hash; return MP_OBJ_FROM_PTR(o); @@ -176,7 +183,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ mp_raise_msg(&mp_type_UnicodeError, NULL); } #endif - return mp_obj_new_str(bufinfo.buf, bufinfo.len, false); + return mp_obj_new_str(bufinfo.buf, bufinfo.len); } } } @@ -205,7 +212,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size if (str_hash == 0) { str_hash = qstr_compute_hash(str_data, str_len); } - mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(&mp_type_bytes, NULL, str_len)); + mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(&mp_type_bytes, NULL, str_len)); o->data = str_data; o->hash = str_hash; return MP_OBJ_FROM_PTR(o); @@ -216,7 +223,10 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size } if (MP_OBJ_IS_SMALL_INT(args[0])) { - uint len = MP_OBJ_SMALL_INT_VALUE(args[0]); + mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]); + if (len < 0) { + mp_raise_ValueError(NULL); + } vstr_t vstr; vstr_init_len(&vstr, len); memset(vstr.buf, 0, len); @@ -226,7 +236,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size // check if argument has the buffer protocol mp_buffer_info_t bufinfo; if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) { - return mp_obj_new_str_of_type(&mp_type_bytes, bufinfo.buf, bufinfo.len); + return mp_obj_new_bytes(bufinfo.buf, bufinfo.len); } vstr_t vstr; @@ -377,8 +387,7 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return mp_obj_new_str_from_vstr(lhs_type, &vstr); } - case MP_BINARY_OP_IN: - /* NOTE `a in b` is `b.__contains__(a)` */ + case MP_BINARY_OP_CONTAINS: return mp_obj_new_bool(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL); //case MP_BINARY_OP_NOT_EQUAL: // This is never passed here @@ -423,7 +432,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) { return MP_OBJ_NEW_SMALL_INT(self_data[index_val]); } else { - return mp_obj_new_str((char*)&self_data[index_val], 1, true); + return mp_obj_new_str_via_qstr((char*)&self_data[index_val], 1); } } else { return MP_OBJ_NULL; // op not supported @@ -654,9 +663,7 @@ STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) { } res->items[idx--] = mp_obj_new_str_of_type(self_type, s + sep_len, last - s - sep_len); last = s; - if (splits > 0) { - splits--; - } + splits--; } if (idx != 0) { // We split less parts than split limit, now go cleanup surplus @@ -1050,7 +1057,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } else { const char *lookup; for (lookup = field_name; lookup < field_name_top && *lookup != '.' && *lookup != '['; lookup++); - mp_obj_t field_q = mp_obj_new_str(field_name, lookup - field_name, true/*?*/); + mp_obj_t field_q = mp_obj_new_str_via_qstr(field_name, lookup - field_name); // should it be via qstr? field_name = lookup; mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP); if (key_elem == NULL) { @@ -1417,7 +1424,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ } ++str; } - mp_obj_t k_obj = mp_obj_new_str((const char*)key, str - key, true); + mp_obj_t k_obj = mp_obj_new_str_via_qstr((const char*)key, str - key); arg = mp_obj_dict_get(dict, k_obj); str++; } @@ -1702,7 +1709,7 @@ STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { // if needle_len is zero then we count each gap between characters as an occurrence if (needle_len == 0) { - return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char*)start, end - start) + 1); + return MP_OBJ_NEW_SMALL_INT(utf8_charlen(start, end - start) + 1); } // count the occurrences @@ -1981,8 +1988,9 @@ const mp_obj_type_t mp_type_bytes = { const mp_obj_str_t mp_const_empty_bytes_obj = {{&mp_type_bytes}, 0, 0, (const byte*)""}; // Create a str/bytes object using the given data. New memory is allocated and -// the data is copied across. -mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len) { +// the data is copied across. This function should only be used if the type is bytes, +// or if the type is str and the string data is known to be not interned. +mp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte* data, size_t len) { mp_obj_str_t *o = m_new_obj(mp_obj_str_t); o->base.type = type; o->len = len; @@ -1996,6 +2004,22 @@ mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, siz return MP_OBJ_FROM_PTR(o); } +// Create a str/bytes object using the given data. If the type is str and the string +// data is already interned, then a qstr object is returned. Otherwise new memory is +// allocated for the object and the data is copied across. +mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len) { + if (type == &mp_type_str) { + return mp_obj_new_str((const char*)data, len); + } else { + return mp_obj_new_bytes(data, len); + } +} + +// Create a str using a qstr to store the data; may use existing or new qstr. +mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len) { + return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); +} + // Create a str/bytes object from the given vstr. The vstr buffer is resized to // the exact length required and then reused for the str/bytes object. The vstr // is cleared and can safely be passed to vstr_free if it was heap allocated. @@ -2026,29 +2050,30 @@ mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { return MP_OBJ_FROM_PTR(o); } -mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already) { - if (make_qstr_if_not_already) { - // use existing, or make a new qstr - return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); +mp_obj_t mp_obj_new_str(const char* data, size_t len) { + qstr q = qstr_find_strn(data, len); + if (q != MP_QSTR_NULL) { + // qstr with this data already exists + return MP_OBJ_NEW_QSTR(q); } else { - qstr q = qstr_find_strn(data, len); - if (q != MP_QSTR_NULL) { - // qstr with this data already exists - return MP_OBJ_NEW_QSTR(q); - } else { - // no existing qstr, don't make one - return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len); - } + // no existing qstr, don't make one + return mp_obj_new_str_copy(&mp_type_str, (const byte*)data, len); } } mp_obj_t mp_obj_str_intern(mp_obj_t str) { GET_STR_DATA_LEN(str, data, len); - return MP_OBJ_NEW_QSTR(qstr_from_strn((const char*)data, len)); + return mp_obj_new_str_via_qstr((const char*)data, len); +} + +mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj) { + size_t len; + const char *data = mp_obj_str_get_data(obj, &len); + return mp_obj_new_str_via_qstr((const char*)data, len); } mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) { - return mp_obj_new_str_of_type(&mp_type_bytes, data, len); + return mp_obj_new_str_copy(&mp_type_bytes, data, len); } bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { @@ -2070,7 +2095,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { } } -STATIC void bad_implicit_conversion(mp_obj_t self_in) { +STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("can't convert to str implicitly"); } else { @@ -2142,7 +2167,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in); GET_STR_DATA_LEN(self->str, str, len); if (self->cur < len) { - mp_obj_t o_out = mp_obj_new_str((const char*)str + self->cur, 1, true); + mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)str + self->cur, 1); self->cur += 1; return o_out; } else { diff --git a/py/objstr.h b/py/objstr.h index 82501a763e..4e55cad091 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -65,6 +65,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len); mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args); +mp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte* data, size_t len); mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len); mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); diff --git a/py/objstringio.c b/py/objstringio.c index 5c50aa3174..b405ee21e3 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -143,6 +143,17 @@ STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, } case MP_STREAM_FLUSH: return 0; + case MP_STREAM_CLOSE: + #if MICROPY_CPYTHON_COMPAT + vstr_free(o->vstr); + o->vstr = NULL; + #else + vstr_clear(o->vstr); + o->vstr->alloc = 0; + o->vstr->len = 0; + o->pos = 0; + #endif + return 0; default: *errcode = MP_EINVAL; return MP_STREAM_ERROR; @@ -159,24 +170,9 @@ STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue); -STATIC mp_obj_t stringio_close(mp_obj_t self_in) { - mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); -#if MICROPY_CPYTHON_COMPAT - vstr_free(self->vstr); - self->vstr = NULL; -#else - vstr_clear(self->vstr); - self->vstr->alloc = 0; - self->vstr->len = 0; - self->pos = 0; -#endif - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close); - STATIC mp_obj_t stringio___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; - return stringio_close(args[0]); + return mp_stream_close(args[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__); @@ -233,7 +229,7 @@ STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&stringio_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, { MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stringio___exit___obj) }, diff --git a/py/objstrunicode.c b/py/objstrunicode.c index a243022a72..ca41a7baa8 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -104,7 +104,7 @@ STATIC mp_obj_t uni_unary_op(mp_unary_op_t op, mp_obj_t self_in) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(str_len != 0); case MP_UNARY_OP_LEN: - return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char *)str_data, str_len)); + return MP_OBJ_NEW_SMALL_INT(utf8_charlen(str_data, str_len)); default: return MP_OBJ_NULL; // op not supported } @@ -216,7 +216,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { ++len; } } - return mp_obj_new_str((const char*)s, len, true); // This will create a one-character string + return mp_obj_new_str_via_qstr((const char*)s, len); // This will create a one-character string } else { return MP_OBJ_NULL; // op not supported } @@ -291,7 +291,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { if (self->cur < len) { const byte *cur = str + self->cur; const byte *end = utf8_next_char(str + self->cur); - mp_obj_t o_out = mp_obj_new_str((const char*)cur, end - cur, true); + mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)cur, end - cur); self->cur += end - cur; return o_out; } else { diff --git a/py/objtype.c b/py/objtype.c index 5b70e8e489..dc9724e5b3 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2018 Damien P. George * Copyright (c) 2014-2016 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -42,19 +42,17 @@ #define DEBUG_printf(...) (void)0 #endif +#define ENABLE_SPECIAL_ACCESSORS \ + (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY) + +#define TYPE_FLAG_IS_SUBCLASSED (0x0001) +#define TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002) + STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); /******************************************************************************/ // instance object -STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, size_t subobjs) { - mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs); - o->base.type = class; - mp_map_init(&o->members, 0); - mp_seq_clear(o->subobj, 0, subobjs, sizeof(*o->subobj)); - return MP_OBJ_FROM_PTR(o); -} - STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) { int count = 0; for (;;) { @@ -68,6 +66,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t } else if (type->parent == NULL) { // No parents so end search here. return count; + #if MICROPY_MULTIPLE_INHERITANCE } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { // Multiple parents, search through them all recursively. const mp_obj_tuple_t *parent_tuple = type->parent; @@ -79,6 +78,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t count += instance_count_native_bases(bt, last_native_base); } return count; + #endif } else { // A single parent, use iteration to continue the search. type = type->parent; @@ -86,6 +86,35 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t } } +// This wrapper function is allows a subclass of a native type to call the +// __init__() method (corresponding to type->make_new) of the native type. +STATIC mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) { + mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]); + const mp_obj_type_t *native_base = NULL; + instance_count_native_bases(self->base.type, &native_base); + self->subobj[0] = native_base->make_new(native_base, n_args - 1, 0, args + 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper); + +#if !MICROPY_CPYTHON_COMPAT +STATIC +#endif +mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_type_t **native_base) { + size_t num_native_bases = instance_count_native_bases(class, native_base); + assert(num_native_bases < 2); + mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, num_native_bases); + o->base.type = class; + mp_map_init(&o->members, 0); + // Initialise the native base-class slot (should be 1 at most) with a valid + // object. It doesn't matter which object, so long as it can be uniquely + // distinguished from a native class that is initialised. + if (num_native_bases != 0) { + o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj); + } + return o; +} + // TODO // This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO // http://python-history.blogspot.com/2010/06/method-resolution-order.html @@ -176,6 +205,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_ if (type->parent == NULL) { DEBUG_printf("mp_obj_class_lookup: No more parents\n"); return; + #if MICROPY_MULTIPLE_INHERITANCE } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { const mp_obj_tuple_t *parent_tuple = type->parent; const mp_obj_t *item = parent_tuple->items; @@ -196,6 +226,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_ // search last base (simple tail recursion elimination) assert(MP_OBJ_IS_TYPE(*item, &mp_type_type)); type = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item); + #endif } else { type = type->parent; } @@ -251,20 +282,6 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { assert(mp_obj_is_instance_type(self)); - const mp_obj_type_t *native_base; - size_t num_native_bases = instance_count_native_bases(self, &native_base); - assert(num_native_bases < 2); - - mp_obj_instance_t *o = MP_OBJ_TO_PTR(mp_obj_new_instance(self, num_native_bases)); - - // This executes only "__new__" part of instance creation. - // TODO: This won't work well for classes with native bases. - // TODO: This is a hack, should be resolved along the lines of - // https://github.com/micropython/micropython/issues/606#issuecomment-43685883 - if (n_args == 1 && *args == MP_OBJ_SENTINEL) { - return MP_OBJ_FROM_PTR(o); - } - // look for __new__ function mp_obj_t init_fn[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { @@ -276,13 +293,22 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size }; mp_obj_class_lookup(&lookup, self); - mp_obj_t new_ret = MP_OBJ_FROM_PTR(o); - if (init_fn[0] == MP_OBJ_SENTINEL) { - // Native type's constructor is what wins - it gets all our arguments, - // and none Python classes are initialized at all. - o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args); - } else if (init_fn[0] != MP_OBJ_NULL) { - // now call Python class __new__ function with all args + const mp_obj_type_t *native_base = NULL; + mp_obj_instance_t *o; + if (init_fn[0] == MP_OBJ_NULL || init_fn[0] == MP_OBJ_SENTINEL) { + // Either there is no __new__() method defined or there is a native + // constructor. In both cases create a blank instance. + o = mp_obj_new_instance(self, &native_base); + + // Since type->make_new() implements both __new__() and __init__() in + // one go, of which the latter may be overridden by the Python subclass, + // we defer (see the end of this function) the call of the native + // constructor to give a chance for the Python __init__() method to call + // said native constructor. + + } else { + // Call Python class __new__ function with all args to create an instance + mp_obj_t new_ret; if (n_args == 0 && n_kw == 0) { mp_obj_t args2[1] = {MP_OBJ_FROM_PTR(self)}; new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, args2); @@ -294,17 +320,20 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw); } - } + // https://docs.python.org/3.4/reference/datamodel.html#object.__new__ + // "If __new__() does not return an instance of cls, then the new + // instance's __init__() method will not be invoked." + if (mp_obj_get_type(new_ret) != self) { + return new_ret; + } - // https://docs.python.org/3.4/reference/datamodel.html#object.__new__ - // "If __new__() does not return an instance of cls, then the new instance's __init__() method will not be invoked." - if (mp_obj_get_type(new_ret) != self) { - return new_ret; + // The instance returned by __new__() becomes the new object + o = MP_OBJ_TO_PTR(new_ret); } - o = MP_OBJ_TO_PTR(new_ret); - // now call Python class __init__ function with all args + // This method has a chance to call super().__init__() to construct a + // possible native base class. init_fn[0] = init_fn[1] = MP_OBJ_NULL; lookup.obj = o; lookup.attr = MP_QSTR___init__; @@ -333,6 +362,12 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size } + // If the type had a native base that was not explicitly initialised + // (constructed) by the Python __init__() method then construct it now. + if (native_base != NULL && o->subobj[0] == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) { + o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args); + } + return MP_OBJ_FROM_PTR(o); } @@ -424,7 +459,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = { [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__, [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__, // MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result - [MP_BINARY_OP_IN] = MP_QSTR___contains__, + [MP_BINARY_OP_CONTAINS] = MP_QSTR___contains__, // All inplace methods are optional, and normal methods will be used // as a fallback. @@ -537,7 +572,6 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); if (elem != NULL) { // object member, always treated as a value - // TODO should we check for properties? dest[0] = elem->value; return; } @@ -568,6 +602,11 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des mp_obj_t member = dest[0]; if (member != MP_OBJ_NULL) { // changes here may may require changes to super_attr, below + if (!(self->base.type->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + // Class doesn't have any special accessors to check so return straightaway + return; + } + #if MICROPY_PY_BUILTINS_PROPERTY if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { // object member is a property; delegate the load to the property @@ -629,11 +668,15 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in); + if (!(self->base.type->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + // Class doesn't have any special accessors so skip their checks + goto skip_special_accessors; + } + #if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS // With property and/or descriptors enabled we need to do a lookup // first in the class dict for the attribute to see if the store should // be delegated. - // Note: this makes all stores slow... how to fix? mp_obj_t member[2] = {MP_OBJ_NULL}; struct class_lookup_data lookup = { .obj = self, @@ -705,9 +748,9 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val } #endif + #if MICROPY_PY_DELATTR_SETATTR if (value == MP_OBJ_NULL) { // delete attribute - #if MICROPY_PY_DELATTR_SETATTR // try __delattr__ first mp_obj_t attr_delattr_method[3]; mp_load_method_maybe(self_in, MP_QSTR___delattr__, attr_delattr_method); @@ -717,13 +760,8 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val mp_call_method_n_kw(1, 0, attr_delattr_method); return true; } - #endif - - mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); - return elem != NULL; } else { // store attribute - #if MICROPY_PY_DELATTR_SETATTR // try __setattr__ first mp_obj_t attr_setattr_method[4]; mp_load_method_maybe(self_in, MP_QSTR___setattr__, attr_setattr_method); @@ -734,14 +772,23 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val mp_call_method_n_kw(2, 0, attr_setattr_method); return true; } - #endif + } + #endif +skip_special_accessors: + + if (value == MP_OBJ_NULL) { + // delete attribute + mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + return elem != NULL; + } else { + // store attribute mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; return true; } } -void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { mp_obj_instance_load_attr(self_in, attr, dest); } else { @@ -876,6 +923,34 @@ STATIC mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, // - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object // - creating a new class (a new type) creates a new mp_obj_type_t +#if ENABLE_SPECIAL_ACCESSORS +STATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { + #if MICROPY_PY_DELATTR_SETATTR + if (key == MP_OBJ_NEW_QSTR(MP_QSTR___setattr__) || key == MP_OBJ_NEW_QSTR(MP_QSTR___delattr__)) { + return true; + } + #endif + #if MICROPY_PY_BUILTINS_PROPERTY + if (MP_OBJ_IS_TYPE(value, &mp_type_property)) { + return true; + } + #endif + #if MICROPY_PY_DESCRIPTORS + static const uint8_t to_check[] = { + MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__, + }; + for (size_t i = 0; i < MP_ARRAY_SIZE(to_check); ++i) { + mp_obj_t dest_temp[2]; + mp_load_method_protected(value, to_check[i], dest_temp, true); + if (dest_temp[0] != MP_OBJ_NULL) { + return true; + } + } + #endif + return false; +} +#endif + STATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); @@ -950,21 +1025,34 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (self->locals_dict != NULL) { assert(self->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now mp_map_t *locals_map = &self->locals_dict->map; + if (locals_map->is_fixed) { + // can't apply delete/store to a fixed map + return; + } if (dest[1] == MP_OBJ_NULL) { // delete attribute mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); - // note that locals_map may be in ROM, so remove will fail in that case if (elem != NULL) { dest[0] = MP_OBJ_NULL; // indicate success } } else { + #if ENABLE_SPECIAL_ACCESSORS + // Check if we add any special accessor methods with this store + if (!(self->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + if (check_for_special_accessors(MP_OBJ_NEW_QSTR(attr), dest[1])) { + if (self->flags & TYPE_FLAG_IS_SUBCLASSED) { + // This class is already subclassed so can't have special accessors added + mp_raise_msg(&mp_type_AttributeError, "can't add special method to already-subclassed class"); + } + self->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + } + } + #endif + // store attribute mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); - // note that locals_map may be in ROM, so add will fail in that case - if (elem != NULL) { - elem->value = make_obj_long_lived(dest[1], 10); - dest[0] = MP_OBJ_NULL; // indicate success - } + elem->value = make_obj_long_lived(dest[1], 10); + dest[0] = MP_OBJ_NULL; // indicate success } } } @@ -981,26 +1069,26 @@ const mp_obj_type_t mp_type_type = { }; mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { - if(!MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)) { - // MicroPython restriction, for now - mp_raise_TypeError("type() argument 2 must be tuple"); + // Verify input objects have expected type + if (!MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)) { + mp_raise_TypeError(NULL); } - if(!MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)) { - // MicroPython restriction, for now - mp_raise_TypeError("type() argument 3 must be dict"); + if (!MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)) { + mp_raise_TypeError(NULL); } // TODO might need to make a copy of locals_dict; at least that's how CPython does it // Basic validation of base classes - size_t len; - mp_obj_t *items; - mp_obj_tuple_get(bases_tuple, &len, &items); - for (size_t i = 0; i < len; i++) { - if(!MP_OBJ_IS_TYPE(items[i], &mp_type_type)) { + uint16_t base_flags = 0; + size_t bases_len; + mp_obj_t *bases_items; + mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items); + for (size_t i = 0; i < bases_len; i++) { + if (!MP_OBJ_IS_TYPE(bases_items[i], &mp_type_type)) { mp_raise_TypeError("type is not an acceptable base type"); } - mp_obj_type_t *t = MP_OBJ_TO_PTR(items[i]); + mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]); // TODO: Verify with CPy, tested on function type if (t->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { @@ -1010,10 +1098,17 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) "type '%q' is not an acceptable base type", t->name); } } + #if ENABLE_SPECIAL_ACCESSORS + if (mp_obj_is_instance_type(t)) { + t->flags |= TYPE_FLAG_IS_SUBCLASSED; + base_flags |= t->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + } + #endif } mp_obj_type_t *o = m_new0_ll(mp_obj_type_t, 1); o->base.type = &mp_type_type; + o->flags = base_flags; o->name = name; o->print = instance_print; o->make_new = mp_obj_instance_make_new; @@ -1026,22 +1121,41 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) //o->iternext = ; not implemented o->buffer_p.get_buffer = instance_get_buffer; - if (len > 0) { + if (bases_len > 0) { // Inherit protocol from a base class. This allows to define an // abstract base class which would translate C-level protocol to // Python method calls, and any subclass inheriting from it will // support this feature. - o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(items[0]))->protocol; + o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(bases_items[0]))->protocol; - if (len >= 2) { + if (bases_len >= 2) { + #if MICROPY_MULTIPLE_INHERITANCE o->parent = MP_OBJ_TO_PTR(bases_tuple); + #else + mp_raise_NotImplementedError("multiple inheritance not supported"); + #endif } else { - o->parent = MP_OBJ_TO_PTR(items[0]); + o->parent = MP_OBJ_TO_PTR(bases_items[0]); } } o->locals_dict = make_dict_long_lived(locals_dict, 10); + #if ENABLE_SPECIAL_ACCESSORS + // Check if the class has any special accessor methods + if (!(o->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { + for (size_t i = 0; i < o->locals_dict->map.alloc; i++) { + if (MP_MAP_SLOT_IS_FILLED(&o->locals_dict->map, i)) { + const mp_map_elem_t *elem = &o->locals_dict->map.table[i]; + if (check_for_special_accessors(elem->key, elem->value)) { + o->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS; + break; + } + } + } + } + #endif + const mp_obj_type_t *native_base; size_t num_native_bases = instance_count_native_bases(o, &native_base); if (num_native_bases > 1) { @@ -1114,49 +1228,69 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { .is_type = false, }; + // Allow a call super().__init__() to reach any native base classes + if (attr == MP_QSTR___init__) { + lookup.meth_offset = offsetof(mp_obj_type_t, make_new); + } + if (type->parent == NULL) { // no parents, do nothing + #if MICROPY_MULTIPLE_INHERITANCE } else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) { const mp_obj_tuple_t *parent_tuple = type->parent; size_t len = parent_tuple->len; const mp_obj_t *items = parent_tuple->items; for (size_t i = 0; i < len; i++) { assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type)); + if (MP_OBJ_TO_PTR(items[i]) == &mp_type_object) { + // The "object" type will be searched at the end of this function, + // and we don't want to lookup native methods in object. + continue; + } mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i])); if (dest[0] != MP_OBJ_NULL) { break; } } - } else { + #endif + } else if (type->parent != &mp_type_object) { mp_obj_class_lookup(&lookup, type->parent); } if (dest[0] != MP_OBJ_NULL) { - mp_obj_t member = dest[0]; - // changes to mp_obj_instance_load_attr may require changes - // here... - #if MICROPY_PY_BUILTINS_PROPERTY - if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { - const mp_obj_t *proxy = mp_obj_property_get(member); - if (proxy[0] == mp_const_none) { - mp_raise_AttributeError("unreadable attribute"); - } else { - dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in); + if (dest[0] == MP_OBJ_SENTINEL) { + // Looked up native __init__ so defer to it + dest[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj); + dest[1] = self->obj; + } else { + mp_obj_t member = dest[0]; + // changes to mp_obj_instance_load_attr may require changes + // here... + #if MICROPY_PY_BUILTINS_PROPERTY + if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { + const mp_obj_t *proxy = mp_obj_property_get(member); + if (proxy[0] == mp_const_none) { + mp_raise_AttributeError("unreadable attribute"); + } else { + dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in); + } } + #endif + #if MICROPY_PY_DESCRIPTORS + mp_obj_t attr_get_method[4]; + mp_load_method_maybe(member, MP_QSTR___get__, attr_get_method); + if (attr_get_method[0] != MP_OBJ_NULL) { + attr_get_method[2] = self_in; + attr_get_method[3] = MP_OBJ_FROM_PTR(mp_obj_get_type(self_in)); + dest[0] = mp_call_method_n_kw(2, 0, attr_get_method); } - #endif - #if MICROPY_PY_DESCRIPTORS - mp_obj_t attr_get_method[4]; - mp_load_method_maybe(member, MP_QSTR___get__, attr_get_method); - if (attr_get_method[0] != MP_OBJ_NULL) { - attr_get_method[2] = self_in; - attr_get_method[3] = MP_OBJ_FROM_PTR(mp_obj_get_type(self_in)); - dest[0] = mp_call_method_n_kw(2, 0, attr_get_method); - } - #endif return; } + // Reset meth_offset so we don't look up any native methods in object, + // because object never takes up the native base-class slot. + lookup.meth_offset = 0; + mp_obj_class_lookup(&lookup, &mp_type_object); } @@ -1196,6 +1330,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { if (self->parent == NULL) { // type has no parents return false; + #if MICROPY_MULTIPLE_INHERITANCE } else if (((mp_obj_base_t*)self->parent)->type == &mp_type_tuple) { // get the base objects (they should be type objects) const mp_obj_tuple_t *parent_tuple = self->parent; @@ -1211,6 +1346,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) { // search last base (simple tail recursion elimination) object = *item; + #endif } else { // type has 1 parent object = MP_OBJ_FROM_PTR(self->parent); diff --git a/py/objtype.h b/py/objtype.h index 52419f3cdc..3fc8c6e1b0 100644 --- a/py/objtype.h +++ b/py/objtype.h @@ -37,8 +37,10 @@ typedef struct _mp_obj_instance_t { // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them } mp_obj_instance_t; -// this needs to be exposed for MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE to work -void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); +#if MICROPY_CPYTHON_COMPAT +// this is needed for object.__new__ +mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *cls, const mp_obj_type_t **native_base); +#endif // these need to be exposed so mp_obj_is_callable can work correctly bool mp_obj_instance_is_callable(mp_obj_t self_in); diff --git a/py/opmethods.c b/py/opmethods.c index 1200ba39ef..247fa5bbc8 100644 --- a/py/opmethods.c +++ b/py/opmethods.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "py/runtime0.h" +#include "py/obj.h" #include "py/builtin.h" STATIC mp_obj_t op_getitem(mp_obj_t self_in, mp_obj_t key_in) { @@ -47,6 +47,6 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_op_delitem_obj, op_delitem); STATIC mp_obj_t op_contains(mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_type_t *type = mp_obj_get_type(lhs_in); - return type->binary_op(MP_BINARY_OP_IN, lhs_in, rhs_in); + return type->binary_op(MP_BINARY_OP_CONTAINS, lhs_in, rhs_in); } MP_DEFINE_CONST_FUN_OBJ_2(mp_op_contains_obj, op_contains); diff --git a/py/parse.c b/py/parse.c index 08a4034012..ab162710d7 100644 --- a/py/parse.c +++ b/py/parse.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -58,15 +58,6 @@ // (un)comment to use rule names; for debugging //#define USE_RULE_NAME (1) -typedef struct _rule_t { - byte rule_id; - byte act; -#ifdef USE_RULE_NAME - const char *rule_name; -#endif - uint16_t arg[]; -} rule_t; - enum { // define rules with a compile function #define DEF_RULE(rule, comp, kind, ...) RULE_##rule, @@ -84,6 +75,8 @@ enum { #undef DEF_RULE_NC }; +// Define an array of actions corresponding to each rule +STATIC const uint8_t rule_act_table[] = { #define or(n) (RULE_ACT_OR | n) #define and(n) (RULE_ACT_AND | n) #define and_ident(n) (RULE_ACT_AND | n | RULE_ACT_ALLOW_IDENT) @@ -91,45 +84,129 @@ enum { #define one_or_more (RULE_ACT_LIST | 2) #define list (RULE_ACT_LIST | 1) #define list_with_end (RULE_ACT_LIST | 3) -#define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t) -#define rule(r) (RULE_ARG_RULE | RULE_##r) -#define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r) -#ifdef USE_RULE_NAME -#define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } }; -#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } }; -#else -#define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; -#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } }; -#endif -#include "py/grammar.h" -#undef or -#undef and -#undef list -#undef list_with_end -#undef tok -#undef rule -#undef opt_rule -#undef one_or_more -#undef DEF_RULE -#undef DEF_RULE_NC -STATIC const rule_t *const rules[] = { -// define rules with a compile function -#define DEF_RULE(rule, comp, kind, ...) &rule_##rule, +#define DEF_RULE(rule, comp, kind, ...) kind, #define DEF_RULE_NC(rule, kind, ...) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC - NULL, // RULE_const_object -// define rules without a compile function + 0, // RULE_const_object + #define DEF_RULE(rule, comp, kind, ...) -#define DEF_RULE_NC(rule, kind, ...) &rule_##rule, +#define DEF_RULE_NC(rule, kind, ...) kind, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + +#undef or +#undef and +#undef and_ident +#undef and_blank +#undef one_or_more +#undef list +#undef list_with_end +}; + +// Define the argument data for each rule, as a combined array +STATIC const uint16_t rule_arg_combined_table[] = { +#define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t) +#define rule(r) (RULE_ARG_RULE | RULE_##r) +#define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r) + +#define DEF_RULE(rule, comp, kind, ...) __VA_ARGS__, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) __VA_ARGS__, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + +#undef tok +#undef rule +#undef opt_rule +}; + +// Macro to create a list of N identifiers where N is the number of variable arguments to the macro +#define RULE_EXPAND(x) x +#define RULE_PADDING(rule, ...) RULE_PADDING2(rule, __VA_ARGS__, RULE_PADDING_IDS(rule)) +#define RULE_PADDING2(rule, ...) RULE_EXPAND(RULE_PADDING3(rule, __VA_ARGS__)) +#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) __VA_ARGS__ +#define RULE_PADDING_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, + +// Use an enum to create constants specifying how much room a rule takes in rule_arg_combined_table +enum { +#define DEF_RULE(rule, comp, kind, ...) RULE_PADDING(rule, __VA_ARGS__) +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) RULE_PADDING(rule, __VA_ARGS__) #include "py/grammar.h" #undef DEF_RULE #undef DEF_RULE_NC }; +// Macro to compute the start of a rule in rule_arg_combined_table +#define RULE_ARG_OFFSET(rule, ...) RULE_ARG_OFFSET2(rule, __VA_ARGS__, RULE_ARG_OFFSET_IDS(rule)) +#define RULE_ARG_OFFSET2(rule, ...) RULE_EXPAND(RULE_ARG_OFFSET3(rule, __VA_ARGS__)) +#define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) _13 +#define RULE_ARG_OFFSET_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r, + +// Use the above enum values to create a table of offsets for each rule's arg +// data, which indexes rule_arg_combined_table. The offsets require 9 bits of +// storage but only the lower 8 bits are stored here. The 9th bit is computed +// in get_rule_arg using the FIRST_RULE_WITH_OFFSET_ABOVE_255 constant. +STATIC const uint8_t rule_arg_offset_table[] = { +#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + 0, // RULE_const_object +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +}; + +// Define a constant that's used to determine the 9th bit of the values in rule_arg_offset_table +static const size_t FIRST_RULE_WITH_OFFSET_ABOVE_255 = +#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule : +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule : +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +0; + +#if USE_RULE_NAME +// Define an array of rule names corresponding to each rule +STATIC const char *const rule_name_table[] = { +#define DEF_RULE(rule, comp, kind, ...) #rule, +#define DEF_RULE_NC(rule, kind, ...) +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC + "", // RULE_const_object +#define DEF_RULE(rule, comp, kind, ...) +#define DEF_RULE_NC(rule, kind, ...) #rule, +#include "py/grammar.h" +#undef DEF_RULE +#undef DEF_RULE_NC +}; +#endif + typedef struct _rule_stack_t { size_t src_line : 8 * sizeof(size_t) - 8; // maximum bits storing source line number size_t rule_id : 8; // this must be large enough to fit largest rule number @@ -164,8 +241,17 @@ typedef struct _parser_t { #endif } parser_t; +STATIC const uint16_t *get_rule_arg(uint8_t r_id) { + size_t off = rule_arg_offset_table[r_id]; + if (r_id >= FIRST_RULE_WITH_OFFSET_ABOVE_255) { + off |= 0x100; + } + return &rule_arg_combined_table[off]; +} + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" + STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) { // use a custom memory allocator to store parse nodes sequentially in large chunks @@ -208,7 +294,7 @@ STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) { } #pragma GCC diagnostic pop -STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t arg_i) { +STATIC void push_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t arg_i) { if (parser->rule_stack_top >= parser->rule_stack_alloc) { rule_stack_t *rs = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC); parser->rule_stack = rs; @@ -216,21 +302,22 @@ STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, siz } rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++]; rs->src_line = src_line; - rs->rule_id = rule->rule_id; + rs->rule_id = rule_id; rs->arg_i = arg_i; } STATIC void push_rule_from_arg(parser_t *parser, size_t arg) { assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE); size_t rule_id = arg & RULE_ARG_ARG_MASK; - push_rule(parser, parser->lexer->tok_line, rules[rule_id], 0); + push_rule(parser, parser->lexer->tok_line, rule_id, 0); } -STATIC void pop_rule(parser_t *parser, const rule_t **rule, size_t *arg_i, size_t *src_line) { +STATIC uint8_t pop_rule(parser_t *parser, size_t *arg_i, size_t *src_line) { parser->rule_stack_top -= 1; - *rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id]; + uint8_t rule_id = parser->rule_stack[parser->rule_stack_top].rule_id; *arg_i = parser->rule_stack[parser->rule_stack_top].arg_i; *src_line = parser->rule_stack[parser->rule_stack_top].src_line; + return rule_id; } bool mp_parse_node_is_const_false(mp_parse_node_t pn) { @@ -316,11 +403,11 @@ void mp_parse_node_print(mp_parse_node_t pn, size_t indent) { #endif } else { size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns); -#ifdef USE_RULE_NAME - printf("%s(%u) (n=%u)\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); -#else + #if USE_RULE_NAME + printf("%s(%u) (n=%u)\n", rule_name_table[MP_PARSE_NODE_STRUCT_KIND(pns)], (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); + #else printf("rule(%u) (n=%u)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n); -#endif + #endif for (size_t i = 0; i < n; i++) { mp_parse_node_print(pns->nodes[i], indent + 2); } @@ -372,7 +459,19 @@ STATIC mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line, return (mp_parse_node_t)pn; } -STATIC void push_result_token(parser_t *parser, const rule_t *rule) { +STATIC mp_parse_node_t mp_parse_node_new_small_int_checked(parser_t *parser, mp_obj_t o_val) { + (void)parser; + mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_val); + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D + // A parse node is only 32-bits and the small-int value must fit in 31-bits + if (((val ^ (val << 1)) & 0xffffffff80000000) != 0) { + return make_node_const_object(parser, 0, o_val); + } + #endif + return mp_parse_node_new_small_int(val); +} + +STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { mp_parse_node_t pn; mp_lexer_t *lex = parser->lexer; if (lex->tok_kind == MP_TOKEN_NAME) { @@ -380,10 +479,10 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { #if MICROPY_COMP_CONST // if name is a standalone identifier, look it up in the table of dynamic constants mp_map_elem_t *elem; - if (rule->rule_id == RULE_atom + if (rule_id == RULE_atom && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) { if (MP_OBJ_IS_SMALL_INT(elem->value)) { - pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(elem->value)); + pn = mp_parse_node_new_small_int_checked(parser, elem->value); } else { pn = make_node_const_object(parser, lex->tok_line, elem->value); } @@ -391,13 +490,13 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); } #else - (void)rule; + (void)rule_id; pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); #endif } else if (lex->tok_kind == MP_TOKEN_INTEGER) { mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex); if (MP_OBJ_IS_SMALL_INT(o)) { - pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(o)); + pn = mp_parse_node_new_small_int_checked(parser, o); } else { pn = make_node_const_object(parser, lex->tok_line, o); } @@ -420,7 +519,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { pn = mp_parse_node_new_leaf(lex->tok_kind == MP_TOKEN_STRING ? MP_PARSE_NODE_STRING : MP_PARSE_NODE_BYTES, qst); } else { // not interned, make a node holding a pointer to the string/bytes object - mp_obj_t o = mp_obj_new_str_of_type( + mp_obj_t o = mp_obj_new_str_copy( lex->tok_kind == MP_TOKEN_STRING ? &mp_type_str : &mp_type_bytes, (const byte*)lex->vstr.buf, lex->vstr.len); pn = make_node_const_object(parser, lex->tok_line, o); @@ -445,12 +544,12 @@ STATIC const mp_rom_map_elem_t mp_constants_table[] = { STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); #endif -STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args); +STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args); #if MICROPY_COMP_CONST_FOLDING -STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t *num_args) { - if (rule->rule_id == RULE_or_test - || rule->rule_id == RULE_and_test) { +STATIC bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *num_args) { + if (rule_id == RULE_or_test + || rule_id == RULE_and_test) { // folding for binary logical ops: or and size_t copy_to = *num_args; for (size_t i = copy_to; i > 0;) { @@ -460,7 +559,7 @@ STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t // always need to keep the last value break; } - if (rule->rule_id == RULE_or_test) { + if (rule_id == RULE_or_test) { if (mp_parse_node_is_const_true(pn)) { // break; @@ -487,7 +586,7 @@ STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t // we did a complete folding if there's only 1 arg left return *num_args == 1; - } else if (rule->rule_id == RULE_not_test_2) { + } else if (rule_id == RULE_not_test_2) { // folding for unary logical op: not mp_parse_node_t pn = peek_result(parser, 0); if (mp_parse_node_is_const_false(pn)) { @@ -505,23 +604,23 @@ STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t return false; } -STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args) { +STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 // it does not do partial folding, eg 1 + 2 + x -> 3 + x mp_obj_t arg0; - if (rule->rule_id == RULE_expr - || rule->rule_id == RULE_xor_expr - || rule->rule_id == RULE_and_expr) { + if (rule_id == RULE_expr + || rule_id == RULE_xor_expr + || rule_id == RULE_and_expr) { // folding for binary ops: | ^ & mp_parse_node_t pn = peek_result(parser, num_args - 1); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { return false; } mp_binary_op_t op; - if (rule->rule_id == RULE_expr) { + if (rule_id == RULE_expr) { op = MP_BINARY_OP_OR; - } else if (rule->rule_id == RULE_xor_expr) { + } else if (rule_id == RULE_xor_expr) { op = MP_BINARY_OP_XOR; } else { op = MP_BINARY_OP_AND; @@ -534,9 +633,9 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args } arg0 = mp_binary_op(op, arg0, arg1); } - } else if (rule->rule_id == RULE_shift_expr - || rule->rule_id == RULE_arith_expr - || rule->rule_id == RULE_term) { + } else if (rule_id == RULE_shift_expr + || rule_id == RULE_arith_expr + || rule_id == RULE_term) { // folding for binary ops: << >> + - * / % // mp_parse_node_t pn = peek_result(parser, num_args - 1); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { @@ -580,7 +679,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args } arg0 = mp_binary_op(op, arg0, arg1); } - } else if (rule->rule_id == RULE_factor_2) { + } else if (rule_id == RULE_factor_2) { // folding for unary ops: + - ~ mp_parse_node_t pn = peek_result(parser, 0); if (!mp_parse_node_get_int_maybe(pn, &arg0)) { @@ -599,7 +698,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args arg0 = mp_unary_op(op, arg0); #if MICROPY_COMP_CONST - } else if (rule->rule_id == RULE_expr_stmt) { + } else if (rule_id == RULE_expr_stmt) { mp_parse_node_t pn1 = peek_result(parser, 0); if (!MP_PARSE_NODE_IS_NULL(pn1) && !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign) @@ -638,7 +737,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args if (qstr_str(id)[0] == '_') { pop_result(parser); // pop const(value) pop_result(parser); // pop id - push_result_rule(parser, 0, rules[RULE_pass_stmt], 0); // replace with "pass" + push_result_rule(parser, 0, RULE_pass_stmt, 0); // replace with "pass" return true; } @@ -654,7 +753,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args #endif #if MICROPY_COMP_MODULE_CONST - } else if (rule->rule_id == RULE_atom_expr_normal) { + } else if (rule_id == RULE_atom_expr_normal) { mp_parse_node_t pn0 = peek_result(parser, 1); mp_parse_node_t pn1 = peek_result(parser, 0); if (!(MP_PARSE_NODE_IS_ID(pn0) @@ -689,7 +788,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args pop_result(parser); } if (MP_OBJ_IS_SMALL_INT(arg0)) { - push_result_node(parser, mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(arg0))); + push_result_node(parser, mp_parse_node_new_small_int_checked(parser, arg0)); } else { // TODO reuse memory for parse node struct? push_result_node(parser, make_node_const_object(parser, 0, arg0)); @@ -699,9 +798,9 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args } #endif -STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args) { +STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) { // optimise away parenthesis around an expression if possible - if (rule->rule_id == RULE_atom_paren) { + if (rule_id == RULE_atom_paren) { // there should be just 1 arg for this rule mp_parse_node_t pn = peek_result(parser, 0); if (MP_PARSE_NODE_IS_NULL(pn)) { @@ -715,11 +814,11 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *ru } #if MICROPY_COMP_CONST_FOLDING - if (fold_logical_constants(parser, rule, &num_args)) { + if (fold_logical_constants(parser, rule_id, &num_args)) { // we folded this rule so return straight away return; } - if (fold_constants(parser, rule, num_args)) { + if (fold_constants(parser, rule_id, num_args)) { // we folded this rule so return straight away return; } @@ -727,7 +826,7 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *ru mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * num_args); pn->source_line = src_line; - pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8); + pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8); for (size_t i = num_args; i > 0; i--) { pn->nodes[i - 1] = pop_result(parser); } @@ -783,14 +882,11 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break; default: top_level_rule = RULE_file_input; } - push_rule(&parser, lex->tok_line, rules[top_level_rule], 0); + push_rule(&parser, lex->tok_line, top_level_rule, 0); // parse! - size_t n, i; // state for the current rule - size_t rule_src_line; // source line for the first token matched by the current rule bool backtrack = false; - const rule_t *rule = NULL; for (;;) { next_rule: @@ -798,19 +894,24 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { break; } - pop_rule(&parser, &rule, &i, &rule_src_line); - n = rule->act & RULE_ACT_ARG_MASK; + // Pop the next rule to process it + size_t i; // state for the current rule + size_t rule_src_line; // source line for the first token matched by the current rule + uint8_t rule_id = pop_rule(&parser, &i, &rule_src_line); + uint8_t rule_act = rule_act_table[rule_id]; + const uint16_t *rule_arg = get_rule_arg(rule_id); + size_t n = rule_act & RULE_ACT_ARG_MASK; - /* + #if 0 // debugging - printf("depth=%d ", parser.rule_stack_top); + printf("depth=" UINT_FMT " ", parser.rule_stack_top); for (int j = 0; j < parser.rule_stack_top; ++j) { printf(" "); } - printf("%s n=%d i=%d bt=%d\n", rule->rule_name, n, i, backtrack); - */ + printf("%s n=" UINT_FMT " i=" UINT_FMT " bt=%d\n", rule_name_table[rule_id], n, i, backtrack); + #endif - switch (rule->act & RULE_ACT_KIND_MASK) { + switch (rule_act & RULE_ACT_KIND_MASK) { case RULE_ACT_OR: if (i > 0 && !backtrack) { goto next_rule; @@ -818,19 +919,19 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { backtrack = false; } for (; i < n; ++i) { - uint16_t kind = rule->arg[i] & RULE_ARG_KIND_MASK; + uint16_t kind = rule_arg[i] & RULE_ARG_KIND_MASK; if (kind == RULE_ARG_TOK) { - if (lex->tok_kind == (rule->arg[i] & RULE_ARG_ARG_MASK)) { - push_result_token(&parser, rule); + if (lex->tok_kind == (rule_arg[i] & RULE_ARG_ARG_MASK)) { + push_result_token(&parser, rule_id); mp_lexer_to_next(lex); goto next_rule; } } else { assert(kind == RULE_ARG_RULE); if (i + 1 < n) { - push_rule(&parser, rule_src_line, rule, i + 1); // save this or-rule + push_rule(&parser, rule_src_line, rule_id, i + 1); // save this or-rule } - push_rule_from_arg(&parser, rule->arg[i]); // push child of or-rule + push_rule_from_arg(&parser, rule_arg[i]); // push child of or-rule goto next_rule; } } @@ -842,7 +943,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // failed, backtrack if we can, else syntax error if (backtrack) { assert(i > 0); - if ((rule->arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) { + if ((rule_arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) { // an optional rule that failed, so continue with next arg push_result_node(&parser, MP_PARSE_NODE_NULL); backtrack = false; @@ -859,13 +960,13 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // progress through the rule for (; i < n; ++i) { - if ((rule->arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + if ((rule_arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { // need to match a token - mp_token_kind_t tok_kind = rule->arg[i] & RULE_ARG_ARG_MASK; + mp_token_kind_t tok_kind = rule_arg[i] & RULE_ARG_ARG_MASK; if (lex->tok_kind == tok_kind) { // matched token if (tok_kind == MP_TOKEN_NAME) { - push_result_token(&parser, rule); + push_result_token(&parser, rule_id); } mp_lexer_to_next(lex); } else { @@ -880,8 +981,8 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } } else { - push_rule(&parser, rule_src_line, rule, i + 1); // save this and-rule - push_rule_from_arg(&parser, rule->arg[i]); // push child of and-rule + push_rule(&parser, rule_src_line, rule_id, i + 1); // save this and-rule + push_rule_from_arg(&parser, rule_arg[i]); // push child of and-rule goto next_rule; } } @@ -892,7 +993,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { #if !MICROPY_ENABLE_DOC_STRING // this code discards lonely statements, such as doc strings - if (input_kind != MP_PARSE_SINGLE_INPUT && rule->rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) { + if (input_kind != MP_PARSE_SINGLE_INPUT && rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) { mp_parse_node_t p = peek_result(&parser, 1); if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p)) || MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_const_object)) { @@ -901,7 +1002,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // Pushing the "pass" rule here will overwrite any RULE_const_object // entry that was on the result stack, allowing the GC to reclaim // the memory from the const object when needed. - push_result_rule(&parser, rule_src_line, rules[RULE_pass_stmt], 0); + push_result_rule(&parser, rule_src_line, RULE_pass_stmt, 0); break; } } @@ -912,8 +1013,8 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { size_t num_not_nil = 0; for (size_t x = n; x > 0;) { --x; - if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { - mp_token_kind_t tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK; + if ((rule_arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + mp_token_kind_t tok_kind = rule_arg[x] & RULE_ARG_ARG_MASK; if (tok_kind == MP_TOKEN_NAME) { // only tokens which were names are pushed to stack i += 1; @@ -928,7 +1029,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } - if (num_not_nil == 1 && (rule->act & RULE_ACT_ALLOW_IDENT)) { + if (num_not_nil == 1 && (rule_act & RULE_ACT_ALLOW_IDENT)) { // this rule has only 1 argument and should not be emitted mp_parse_node_t pn = MP_PARSE_NODE_NULL; for (size_t x = 0; x < i; ++x) { @@ -941,19 +1042,19 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } else { // this rule must be emitted - if (rule->act & RULE_ACT_ADD_BLANK) { + if (rule_act & RULE_ACT_ADD_BLANK) { // and add an extra blank node at the end (used by the compiler to store data) push_result_node(&parser, MP_PARSE_NODE_NULL); i += 1; } - push_result_rule(&parser, rule_src_line, rule, i); + push_result_rule(&parser, rule_src_line, rule_id, i); } break; } default: { - assert((rule->act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST); + assert((rule_act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST); // n=2 is: item item* // n=1 is: item (sep item)* @@ -991,13 +1092,13 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } else { for (;;) { - size_t arg = rule->arg[i & 1 & n]; + size_t arg = rule_arg[i & 1 & n]; if ((arg & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { if (lex->tok_kind == (arg & RULE_ARG_ARG_MASK)) { if (i & 1 & n) { // separators which are tokens are not pushed to result stack } else { - push_result_token(&parser, rule); + push_result_token(&parser, rule_id); } mp_lexer_to_next(lex); // got element of list, so continue parsing list @@ -1010,7 +1111,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } } else { assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE); - push_rule(&parser, rule_src_line, rule, i + 1); // save this list-rule + push_rule(&parser, rule_src_line, rule_id, i + 1); // save this list-rule push_rule_from_arg(&parser, arg); // push child of list-rule goto next_rule; } @@ -1020,7 +1121,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // compute number of elements in list, result in i i -= 1; - if ((n & 1) && (rule->arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { + if ((n & 1) && (rule_arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) { // don't count separators when they are tokens i = (i + 1) / 2; } @@ -1029,12 +1130,12 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // list matched single item if (had_trailing_sep) { // if there was a trailing separator, make a list of a single item - push_result_rule(&parser, rule_src_line, rule, i); + push_result_rule(&parser, rule_src_line, rule_id, i); } else { // just leave single item on stack (ie don't wrap in a list) } } else { - push_result_rule(&parser, rule_src_line, rule, i); + push_result_rule(&parser, rule_src_line, rule_id, i); } break; } diff --git a/py/parsenum.c b/py/parsenum.c index bacf4f442c..e3644b1711 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -83,6 +83,8 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m mp_uint_t dig = *str; if ('0' <= dig && dig <= '9') { dig -= '0'; + } else if (dig == '_') { + continue; } else { dig |= 0x20; // make digit lower-case if ('a' <= dig && dig <= 'z') { @@ -170,6 +172,19 @@ typedef enum { mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex) { #if MICROPY_PY_BUILTINS_FLOAT + +// DEC_VAL_MAX only needs to be rough and is used to retain precision while not overflowing +// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define DEC_VAL_MAX 1e20F +#define SMALL_NORMAL_VAL (1e-37F) +#define SMALL_NORMAL_EXP (-37) +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define DEC_VAL_MAX 1e200 +#define SMALL_NORMAL_VAL (1e-307) +#define SMALL_NORMAL_EXP (-307) +#endif + const char *top = str + len; mp_float_t dec_val = 0; bool dec_neg = false; @@ -214,20 +229,32 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool // string should be a decimal number parse_dec_in_t in = PARSE_DEC_IN_INTG; bool exp_neg = false; - mp_float_t frac_mult = 0.1; - mp_int_t exp_val = 0; + int exp_val = 0; + int exp_extra = 0; while (str < top) { - mp_uint_t dig = *str++; + unsigned int dig = *str++; if ('0' <= dig && dig <= '9') { dig -= '0'; if (in == PARSE_DEC_IN_EXP) { - exp_val = 10 * exp_val + dig; + // don't overflow exp_val when adding next digit, instead just truncate + // it and the resulting float will still be correct, either inf or 0.0 + // (use INT_MAX/2 to allow adding exp_extra at the end without overflow) + if (exp_val < (INT_MAX / 2 - 9) / 10) { + exp_val = 10 * exp_val + dig; + } } else { - if (in == PARSE_DEC_IN_FRAC) { - dec_val += dig * frac_mult; - frac_mult *= MICROPY_FLOAT_CONST(0.1); - } else { + if (dec_val < DEC_VAL_MAX) { + // dec_val won't overflow so keep accumulating dec_val = 10 * dec_val + dig; + if (in == PARSE_DEC_IN_FRAC) { + --exp_extra; + } + } else { + // dec_val might overflow and we anyway can't represent more digits + // of precision, so ignore the digit and just adjust the exponent + if (in == PARSE_DEC_IN_INTG) { + ++exp_extra; + } } } } else if (in == PARSE_DEC_IN_INTG && dig == '.') { @@ -248,6 +275,8 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool } else if (allow_imag && (dig | 0x20) == 'j') { imag = true; break; + } else if (dig == '_') { + continue; } else { // unknown character str--; @@ -260,7 +289,12 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool exp_val = -exp_val; } - // apply the exponent + // apply the exponent, making sure it's not a subnormal value + exp_val += exp_extra; + if (exp_val < SMALL_NORMAL_EXP) { + exp_val -= SMALL_NORMAL_EXP; + dec_val *= SMALL_NORMAL_VAL; + } dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val); } @@ -289,11 +323,13 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool return mp_obj_new_complex(0, dec_val); } else if (force_complex) { return mp_obj_new_complex(dec_val, 0); + } #else if (imag || force_complex) { raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "complex values not supported"), lex); + } #endif - } else { + else { return mp_obj_new_float(dec_val); } diff --git a/py/persistentcode.c b/py/persistentcode.c index ba126a3fb2..290797a7c9 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -199,7 +199,11 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) { // create raw_code and return it mp_raw_code_t *rc = mp_emit_glue_new_raw_code(); - mp_emit_glue_assign_bytecode(rc, bytecode, bc_len, const_table, + mp_emit_glue_assign_bytecode(rc, bytecode, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + bc_len, + #endif + const_table, #if MICROPY_PERSISTENT_CODE_SAVE n_obj, n_raw_code, #endif diff --git a/py/py.mk b/py/py.mk index e934c3a83f..cad8b53ec1 100644 --- a/py/py.mk +++ b/py/py.mk @@ -13,6 +13,9 @@ ifneq ($(QSTR_AUTOGEN_DISABLE),1) QSTR_DEFS_COLLECTED = $(HEADER_BUILD)/qstrdefs.collected.h endif +# Any files listed by this variable will cause a full regeneration of qstrs +QSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h + # some code is performance bottleneck and compiled with other optimization options CSUPEROPT = -O3 @@ -101,8 +104,9 @@ $(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) endif # py object files -PY_O_BASENAME = \ +PY_CORE_O_BASENAME = $(addprefix py/,\ mpstate.o \ + nlr.o \ nlrx86.o \ nlrx64.o \ nlrthumb.o \ @@ -111,6 +115,7 @@ PY_O_BASENAME = \ malloc.o \ gc.o \ gc_long_lived.o \ + pystack.o \ qstr.o \ vstr.o \ mpprint.o \ @@ -157,6 +162,7 @@ PY_O_BASENAME = \ objcell.o \ objclosure.o \ objcomplex.o \ + objdeque.o \ objdict.o \ objenumerate.o \ objexcept.o \ @@ -213,41 +219,49 @@ PY_O_BASENAME = \ repl.o \ smallint.o \ frozenmod.o \ - ../extmod/moductypes.o \ - ../extmod/modujson.o \ - ../extmod/modure.o \ - ../extmod/moduzlib.o \ - ../extmod/moduheapq.o \ - ../extmod/modutimeq.o \ - ../extmod/moduhashlib.o \ - ../extmod/modubinascii.o \ - ../extmod/virtpin.o \ - ../extmod/machine_mem.o \ - ../extmod/machine_pinbase.o \ - ../extmod/machine_signal.o \ - ../extmod/machine_pulse.o \ - ../extmod/machine_i2c.o \ - ../extmod/machine_spi.o \ - ../extmod/modussl_axtls.o \ - ../extmod/modussl_mbedtls.o \ - ../extmod/modurandom.o \ - ../extmod/moduselect.o \ - ../extmod/modwebsocket.o \ - ../extmod/modwebrepl.o \ - ../extmod/modframebuf.o \ - ../extmod/vfs.o \ - ../extmod/vfs_reader.o \ - ../extmod/vfs_fat.o \ - ../extmod/vfs_fat_diskio.o \ - ../extmod/vfs_fat_file.o \ - ../extmod/vfs_fat_misc.o \ - ../extmod/utime_mphal.o \ - ../extmod/uos_dupterm.o \ - ../lib/embed/abort_.o \ - ../lib/utils/printf.o \ + ) + +PY_EXTMOD_O_BASENAME = \ + extmod/moductypes.o \ + extmod/modujson.o \ + extmod/modure.o \ + extmod/moduzlib.o \ + extmod/moduheapq.o \ + extmod/modutimeq.o \ + extmod/moduhashlib.o \ + extmod/modubinascii.o \ + extmod/virtpin.o \ + extmod/machine_mem.o \ + extmod/machine_pinbase.o \ + extmod/machine_signal.o \ + extmod/machine_pulse.o \ + extmod/machine_i2c.o \ + extmod/machine_spi.o \ + extmod/modussl_axtls.o \ + extmod/modussl_mbedtls.o \ + extmod/modurandom.o \ + extmod/moduselect.o \ + extmod/modwebsocket.o \ + extmod/modwebrepl.o \ + extmod/modframebuf.o \ + extmod/vfs.o \ + extmod/vfs_reader.o \ + extmod/vfs_posix.o \ + extmod/vfs_posix_file.o \ + extmod/vfs_fat.o \ + extmod/vfs_fat_diskio.o \ + extmod/vfs_fat_file.o \ + extmod/utime_mphal.o \ + extmod/uos_dupterm.o \ + lib/embed/abort_.o \ + lib/utils/printf.o \ # prepend the build destination prefix to the py object files -PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) +PY_CORE_O = $(addprefix $(BUILD)/, $(PY_CORE_O_BASENAME)) +PY_EXTMOD_O = $(addprefix $(BUILD)/, $(PY_EXTMOD_O_BASENAME)) + +# this is a convenience variable for ports that want core, extmod and frozen code +PY_O = $(PY_CORE_O) $(PY_EXTMOD_O) # object file for frozen files ifneq ($(FROZEN_DIR),) @@ -263,8 +277,8 @@ PY_O += $(BUILD)/frozen_mpy.o endif # Sources that may contain qstrings -SRC_QSTR_IGNORE = nlr% emitnx86% emitnx64% emitnthumb% emitnarm% emitnxtensa% -SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_O_BASENAME:.o=.c)) emitnative.c) +SRC_QSTR_IGNORE = py/nlr% +SRC_QSTR = $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) $(PY_EXTMOD_O_BASENAME:.o=.c) # Anything that depends on FORCE will be considered out-of-date FORCE: @@ -291,28 +305,6 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_C # that the function preludes are of a minimal and predictable form. $(PY_BUILD)/nlr%.o: CFLAGS += -Os -# emitters - -$(PY_BUILD)/emitnx64.o: CFLAGS += -DN_X64 -$(PY_BUILD)/emitnx64.o: py/emitnative.c - $(call compile_c) - -$(PY_BUILD)/emitnx86.o: CFLAGS += -DN_X86 -$(PY_BUILD)/emitnx86.o: py/emitnative.c - $(call compile_c) - -$(PY_BUILD)/emitnthumb.o: CFLAGS += -DN_THUMB -$(PY_BUILD)/emitnthumb.o: py/emitnative.c - $(call compile_c) - -$(PY_BUILD)/emitnarm.o: CFLAGS += -DN_ARM -$(PY_BUILD)/emitnarm.o: py/emitnative.c - $(call compile_c) - -$(PY_BUILD)/emitnxtensa.o: CFLAGS += -DN_XTENSA -$(PY_BUILD)/emitnxtensa.o: py/emitnative.c - $(call compile_c) - # optimising gc for speed; 5ms down to 4ms on pybv2 $(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT) diff --git a/py/pystack.c b/py/pystack.c new file mode 100644 index 0000000000..552e59d537 --- /dev/null +++ b/py/pystack.c @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" + +#if MICROPY_ENABLE_PYSTACK + +void mp_pystack_init(void *start, void *end) { + MP_STATE_THREAD(pystack_start) = start; + MP_STATE_THREAD(pystack_end) = end; + MP_STATE_THREAD(pystack_cur) = start; +} + +void *mp_pystack_alloc(size_t n_bytes) { + n_bytes = (n_bytes + (MICROPY_PYSTACK_ALIGN - 1)) & ~(MICROPY_PYSTACK_ALIGN - 1); + #if MP_PYSTACK_DEBUG + n_bytes += MICROPY_PYSTACK_ALIGN; + #endif + if (MP_STATE_THREAD(pystack_cur) + n_bytes > MP_STATE_THREAD(pystack_end)) { + // out of memory in the pystack + nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, + MP_OBJ_NEW_QSTR(MP_QSTR_pystack_space_exhausted))); + } + void *ptr = MP_STATE_THREAD(pystack_cur); + MP_STATE_THREAD(pystack_cur) += n_bytes; + #if MP_PYSTACK_DEBUG + *(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN) = n_bytes; + #endif + return ptr; +} + +#endif diff --git a/py/pystack.h b/py/pystack.h new file mode 100644 index 0000000000..82ac3743d1 --- /dev/null +++ b/py/pystack.h @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_PYSTACK_H +#define MICROPY_INCLUDED_PY_PYSTACK_H + +#include "py/mpstate.h" + +// Enable this debugging option to check that the amount of memory freed is +// consistent with amounts that were previously allocated. +#define MP_PYSTACK_DEBUG (0) + +#if MICROPY_ENABLE_PYSTACK + +void mp_pystack_init(void *start, void *end); +void *mp_pystack_alloc(size_t n_bytes); + +// This function can free multiple continuous blocks at once: just pass the +// pointer to the block that was allocated first and it and all subsequently +// allocated blocks will be freed. +static inline void mp_pystack_free(void *ptr) { + assert((uint8_t*)ptr >= MP_STATE_THREAD(pystack_start)); + assert((uint8_t*)ptr <= MP_STATE_THREAD(pystack_cur)); + #if MP_PYSTACK_DEBUG + size_t n_bytes_to_free = MP_STATE_THREAD(pystack_cur) - (uint8_t*)ptr; + size_t n_bytes = *(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN); + while (n_bytes < n_bytes_to_free) { + n_bytes += *(size_t*)(MP_STATE_THREAD(pystack_cur) - n_bytes - MICROPY_PYSTACK_ALIGN); + } + if (n_bytes != n_bytes_to_free) { + mp_printf(&mp_plat_print, "mp_pystack_free() failed: %u != %u\n", (uint)n_bytes_to_free, + (uint)*(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN)); + assert(0); + } + #endif + MP_STATE_THREAD(pystack_cur) = (uint8_t*)ptr; +} + +static inline void mp_pystack_realloc(void *ptr, size_t n_bytes) { + mp_pystack_free(ptr); + mp_pystack_alloc(n_bytes); +} + +static inline size_t mp_pystack_usage(void) { + return MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start); +} + +static inline size_t mp_pystack_limit(void) { + return MP_STATE_THREAD(pystack_end) - MP_STATE_THREAD(pystack_start); +} + +#endif + +#if !MICROPY_ENABLE_PYSTACK + +#define mp_local_alloc(n_bytes) alloca(n_bytes) + +static inline void mp_local_free(void *ptr) { + (void)ptr; +} + +static inline void *mp_nonlocal_alloc(size_t n_bytes) { + return m_new(uint8_t, n_bytes); +} + +static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) { + return m_renew(uint8_t, ptr, old_n_bytes, new_n_bytes); +} + +static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) { + m_del(uint8_t, ptr, n_bytes); +} + +#else + +static inline void *mp_local_alloc(size_t n_bytes) { + return mp_pystack_alloc(n_bytes); +} + +static inline void mp_local_free(void *ptr) { + mp_pystack_free(ptr); +} + +static inline void *mp_nonlocal_alloc(size_t n_bytes) { + return mp_pystack_alloc(n_bytes); +} + +static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) { + (void)old_n_bytes; + mp_pystack_realloc(ptr, new_n_bytes); + return ptr; +} + +static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) { + (void)n_bytes; + mp_pystack_free(ptr); +} + +#endif + +#endif // MICROPY_INCLUDED_PY_PYSTACK_H diff --git a/py/qstr.c b/py/qstr.c index de4dc6240a..c68f3dfec6 100755 --- a/py/qstr.c +++ b/py/qstr.c @@ -128,14 +128,12 @@ void qstr_init(void) { STATIC const byte *find_qstr(qstr q) { // search pool for this qstr - for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL; pool = pool->prev) { - if (q >= pool->total_prev_len) { - return pool->qstrs[q - pool->total_prev_len]; - } + // total_prev_len==0 in the final pool, so the loop will always terminate + qstr_pool_t *pool = MP_STATE_VM(last_pool); + while (q < pool->total_prev_len) { + pool = pool->prev; } - - // not found - return 0; + return pool->qstrs[q - pool->total_prev_len]; } // qstr_mutex must be taken while in this function @@ -248,29 +246,6 @@ qstr qstr_from_strn(const char *str, size_t len) { return q; } -byte *qstr_build_start(size_t len, byte **q_ptr) { - assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN))); - *q_ptr = m_new(byte, MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1); - Q_SET_LENGTH(*q_ptr, len); - return Q_GET_DATA(*q_ptr); -} - -qstr qstr_build_end(byte *q_ptr) { - QSTR_ENTER(); - qstr q = qstr_find_strn((const char*)Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr)); - if (q == 0) { - size_t len = Q_GET_LENGTH(q_ptr); - mp_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len); - Q_SET_HASH(q_ptr, hash); - q_ptr[MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len] = '\0'; - q = qstr_add(gc_make_long_lived(q_ptr)); - } else { - m_del(byte, q_ptr, Q_GET_ALLOC(q_ptr)); - } - QSTR_EXIT(); - return q; -} - mp_uint_t qstr_hash(qstr q) { return Q_GET_HASH(find_qstr(q)); } diff --git a/py/qstr.h b/py/qstr.h index e2bdcc351e..f4375ee0e9 100644 --- a/py/qstr.h +++ b/py/qstr.h @@ -56,6 +56,7 @@ typedef struct _qstr_pool_t { } qstr_pool_t; #define QSTR_FROM_STR_STATIC(s) (qstr_from_strn((s), strlen(s))) +#define QSTR_TOTAL() (MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len) void qstr_init(void); @@ -65,9 +66,6 @@ qstr qstr_find_strn(const char *str, size_t str_len); // returns MP_QSTR_NULL if qstr qstr_from_str(const char *str); qstr qstr_from_strn(const char *str, size_t len); -byte *qstr_build_start(size_t len, byte **q_ptr); -qstr qstr_build_end(byte *q_ptr); - mp_uint_t qstr_hash(qstr q); const char *qstr_str(qstr q); size_t qstr_len(qstr q); diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 4ded5be084..a609058120 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -40,6 +40,7 @@ Q(/) Q(%#o) Q(%#x) Q({:#b}) +Q( ) Q(\n) Q(maximum recursion depth exceeded) Q() @@ -51,3 +52,7 @@ Q() Q() Q() Q(utf-8) + +#if MICROPY_ENABLE_PYSTACK +Q(pystack exhausted) +#endif diff --git a/py/reader.c b/py/reader.c index c4d18d53dc..80364104bb 100644 --- a/py/reader.c +++ b/py/reader.c @@ -124,6 +124,8 @@ void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) { reader->close = mp_reader_posix_close; } +#if !MICROPY_VFS_POSIX +// If MICROPY_VFS_POSIX is defined then this function is provided by the VFS layer void mp_reader_new_file(mp_reader_t *reader, const char *filename) { int fd = open(filename, O_RDONLY, 0644); if (fd < 0) { @@ -131,5 +133,6 @@ void mp_reader_new_file(mp_reader_t *reader, const char *filename) { } mp_reader_new_file_from_fd(reader, fd, true); } +#endif #endif diff --git a/py/repl.c b/py/repl.c index 7e8922e19a..da0fefb3a9 100644 --- a/py/repl.c +++ b/py/repl.c @@ -27,6 +27,7 @@ #include #include "py/obj.h" #include "py/runtime.h" +#include "py/builtin.h" #include "py/repl.h" #if MICROPY_HELPER_REPL @@ -105,8 +106,13 @@ bool mp_repl_continue_with_input(const char *input) { } } - // continue if unmatched brackets or quotes - if (n_paren > 0 || n_brack > 0 || n_brace > 0 || in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) { + // continue if unmatched 3-quotes + if (in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) { + return true; + } + + // continue if unmatched brackets, but only if not in a 1-quote + if ((n_paren > 0 || n_brack > 0 || n_brace > 0) && in_quote == Q_NONE) { return true; } @@ -136,8 +142,11 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print } } - // begin search in locals dict - mp_obj_dict_t *dict = mp_locals_get(); + size_t nqstr = QSTR_TOTAL(); + + // begin search in outer global dict which is accessed from __main__ + mp_obj_t obj = MP_OBJ_FROM_PTR(&mp_module___main__); + mp_obj_t dest[2]; for (;;) { // get next word in string to complete @@ -148,43 +157,20 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print size_t s_len = str - s_start; if (str < top) { - // a complete word, lookup in current dict - - mp_obj_t obj = MP_OBJ_NULL; - for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - size_t d_len; - const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); - if (s_len == d_len && strncmp(s_start, d_str, d_len) == 0) { - obj = dict->map.table[i].value; - break; - } - } + // a complete word, lookup in current object + qstr q = qstr_find_strn(s_start, s_len); + if (q == MP_QSTR_NULL) { + // lookup will fail + return 0; } + mp_load_method_protected(obj, q, dest, true); + obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found if (obj == MP_OBJ_NULL) { // lookup failed return 0; } - // found an object of this name; try to get its dict - if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) { - dict = mp_obj_module_get_globals(obj); - } else { - mp_obj_type_t *type; - if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) { - type = MP_OBJ_TO_PTR(obj); - } else { - type = mp_obj_get_type(obj); - } - if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) { - dict = type->locals_dict; - } else { - // obj has no dict - return 0; - } - } - // skip '.' to move to next word ++str; @@ -192,14 +178,15 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print // end of string, do completion on this partial name // look for matches - int n_found = 0; const char *match_str = NULL; size_t match_len = 0; - for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - size_t d_len; - const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); - if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + qstr q_first = 0, q_last = 0; + for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) { + size_t d_len; + const char *d_str = (const char*)qstr_data(q, &d_len); + if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + mp_load_method_protected(obj, q, dest, true); + if (dest[0] != MP_OBJ_NULL) { if (match_str == NULL) { match_str = d_str; match_len = d_len; @@ -213,13 +200,16 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print } } } - ++n_found; + if (q_first == 0) { + q_first = q; + } + q_last = q; } } } // nothing found - if (n_found == 0) { + if (q_first == 0) { // If there're no better alternatives, and if it's first word // in the line, try to complete "import". if (s_start == org_str) { @@ -234,7 +224,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print } // 1 match found, or multiple matches with a common prefix - if (n_found == 1 || match_len > s_len) { + if (q_first == q_last || match_len > s_len) { *compl_str = match_str + s_len; return match_len - s_len; } @@ -245,11 +235,12 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print #define MAX_LINE_LEN (4 * WORD_SLOT_LEN) int line_len = MAX_LINE_LEN; // force a newline for first word - for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - size_t d_len; - const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); - if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + for (qstr q = q_first; q <= q_last; ++q) { + size_t d_len; + const char *d_str = (const char*)qstr_data(q, &d_len); + if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + mp_load_method_protected(obj, q, dest, true); + if (dest[0] != MP_OBJ_NULL) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; if (gap < 2) { gap += WORD_SLOT_LEN; diff --git a/py/runtime.c b/py/runtime.c index a7ff57a47f..a9c0ef1e2f 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -95,8 +95,10 @@ void mp_init(void) { MICROPY_PORT_INIT_FUNC; #endif + #if MICROPY_ENABLE_COMPILER // optimization disabled by default MP_STATE_VM(mp_optimise_value) = 0; + #endif // init global module dict mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3); @@ -118,7 +120,6 @@ void mp_init(void) { for (size_t i = 0; i < MICROPY_PY_OS_DUPTERM; ++i) { MP_STATE_VM(dupterm_objs[i]) = MP_OBJ_NULL; } - MP_STATE_VM(dupterm_arr_obj) = MP_OBJ_NULL; #endif #ifdef MICROPY_FSUSERMOUNT @@ -246,7 +247,7 @@ void mp_delete_global(qstr qst) { } mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { - DEBUG_OP_printf("unary " UINT_FMT " %p\n", op, arg); + DEBUG_OP_printf("unary " UINT_FMT " %q %p\n", op, mp_unary_op_method_name[op], arg); if (op == MP_UNARY_OP_NOT) { // "not x" is the negative of whether "x" is true per Python semantics @@ -307,7 +308,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { } mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { - DEBUG_OP_printf("binary " UINT_FMT " %p %p\n", op, lhs, rhs); + DEBUG_OP_printf("binary " UINT_FMT " %q %p %p\n", op, mp_binary_op_method_name[op], lhs, rhs); // TODO correctly distinguish inplace operators for mutable objects // lookup logic that CPython uses for +=: @@ -445,7 +446,6 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { // use standard precision return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); } - break; } case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: @@ -520,10 +520,10 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { return MP_OBJ_FROM_PTR(tuple); } - case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); break; - case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); break; - case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); break; - case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); break; + case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); + case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); + case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); + case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); default: goto unsupported_op; @@ -555,38 +555,12 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { } } - /* deal with `in` - * - * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch - * needs to go below with swapped arguments - */ + // Convert MP_BINARY_OP_IN to MP_BINARY_OP_CONTAINS with swapped args. if (op == MP_BINARY_OP_IN) { - mp_obj_type_t *type = mp_obj_get_type(rhs); - if (type->binary_op != NULL) { - mp_obj_t res = type->binary_op(op, rhs, lhs); - if (res != MP_OBJ_NULL) { - return res; - } - } - if (type->getiter != NULL) { - /* second attempt, walk the iterator */ - mp_obj_iter_buf_t iter_buf; - mp_obj_t iter = mp_getiter(rhs, &iter_buf); - mp_obj_t next; - while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { - if (mp_obj_equal(next, lhs)) { - return mp_const_true; - } - } - return mp_const_false; - } - - if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - mp_raise_TypeError("object not iterable"); - } else { - mp_raise_TypeError_varg( - "'%s' object is not iterable", mp_obj_get_type_str(rhs)); - } + op = MP_BINARY_OP_CONTAINS; + mp_obj_t temp = lhs; + lhs = rhs; + rhs = temp; } // generic binary_op supplied by type @@ -615,6 +589,20 @@ generic_binary_op: } #endif + if (op == MP_BINARY_OP_CONTAINS) { + // If type didn't support containment then explicitly walk the iterator. + // mp_getiter will raise the appropriate exception if lhs is not iterable. + mp_obj_iter_buf_t iter_buf; + mp_obj_t iter = mp_getiter(lhs, &iter_buf); + mp_obj_t next; + while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + if (mp_obj_equal(next, rhs)) { + return mp_const_true; + } + } + return mp_const_false; + } + unsupported_op: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_raise_TypeError("unsupported type for operator"); @@ -712,7 +700,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // allocate memory for the new array of args args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len); - args2 = m_new(mp_obj_t, args2_alloc); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); // copy the self if (self != MP_OBJ_NULL) { @@ -733,7 +721,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // allocate memory for the new array of args args2_alloc = 1 + n_args + len + 2 * (n_kw + kw_dict_len); - args2 = m_new(mp_obj_t, args2_alloc); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); // copy the self if (self != MP_OBJ_NULL) { @@ -749,7 +737,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ // allocate memory for the new array of args args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len) + 3; - args2 = m_new(mp_obj_t, args2_alloc); + args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t)); // copy the self if (self != MP_OBJ_NULL) { @@ -766,7 +754,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (args2_len >= args2_alloc) { - args2 = m_renew(mp_obj_t, args2, args2_alloc, args2_alloc * 2); + args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), args2_alloc * 2 * sizeof(mp_obj_t)); args2_alloc *= 2; } args2[args2_len++] = item; @@ -792,8 +780,8 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ if (MP_MAP_SLOT_IS_FILLED(map, i)) { // the key must be a qstr, so intern it if it's a string mp_obj_t key = map->table[i].key; - if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { - key = mp_obj_str_intern(key); + if (!MP_OBJ_IS_QSTR(key)) { + key = mp_obj_str_intern_checked(key); } args2[args2_len++] = key; args2[args2_len++] = map->table[i].value; @@ -817,13 +805,13 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ if (new_alloc < 4) { new_alloc = 4; } - args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc); + args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), new_alloc * sizeof(mp_obj_t)); args2_alloc = new_alloc; } // the key must be a qstr, so intern it if it's a string - if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { - key = mp_obj_str_intern(key); + if (!MP_OBJ_IS_QSTR(key)) { + key = mp_obj_str_intern_checked(key); } // get the value corresponding to the key @@ -849,7 +837,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob mp_call_prepare_args_n_kw_var(have_self, n_args_n_kw, args, &out_args); mp_obj_t res = mp_call_function_n_kw(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); - m_del(mp_obj_t, out_args.args, out_args.n_alloc); + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); return res; } @@ -1144,6 +1132,22 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { } } +// Acts like mp_load_method_maybe but catches AttributeError, and all other exceptions if requested +void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_load_method_maybe(obj, attr, dest); + nlr_pop(); + } else { + if (!catch_all_exc + && !mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type), + MP_OBJ_FROM_PTR(&mp_type_AttributeError))) { + // Re-raise the exception + nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); + } + } +} + void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value); mp_obj_type_t *type = mp_obj_get_type(base); @@ -1304,13 +1308,12 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th if (type->iternext != NULL && send_value == mp_const_none) { mp_obj_t ret = type->iternext(self_in); + *ret_val = ret; if (ret != MP_OBJ_STOP_ITERATION) { - *ret_val = ret; return MP_VM_RETURN_YIELD; } else { // Emulate raise StopIteration() // Special case, handled in vm.c - *ret_val = MP_OBJ_NULL; return MP_VM_RETURN_NORMAL; } } @@ -1372,7 +1375,7 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th // will be propagated up. This behavior is approved by test_pep380.py // test_delegation_of_close_to_non_generator(), // test_delegating_throw_to_non_generator() - *ret_val = throw_value; + *ret_val = mp_make_raise_obj(throw_value); return MP_VM_RETURN_EXCEPTION; } } @@ -1426,6 +1429,8 @@ import_error: return dest[0]; } + #if MICROPY_ENABLE_EXTERNAL_IMPORT + // See if it's a package, then can try FS import if (!mp_obj_is_package(module)) { goto import_error; @@ -1436,11 +1441,12 @@ import_error: const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len); const uint dot_name_len = pkg_name_len + 1 + qstr_len(name); - char *dot_name = alloca(dot_name_len); + char *dot_name = mp_local_alloc(dot_name_len); memcpy(dot_name, pkg_name, pkg_name_len); dot_name[pkg_name_len] = '.'; memcpy(dot_name + pkg_name_len + 1, qstr_str(name), qstr_len(name)); qstr dot_name_q = qstr_from_strn(dot_name, dot_name_len); + mp_local_free(dot_name); mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(dot_name_q); @@ -1451,6 +1457,13 @@ import_error: // TODO lookup __import__ and call that instead of going straight to builtin implementation return mp_builtin___import__(5, args); + + #else + + // Package import not supported with external imports disabled + goto import_error; + + #endif } void mp_import_all(mp_obj_t module) { @@ -1585,3 +1598,10 @@ NORETURN void mp_raise_OSError(int errno_) { NORETURN void mp_raise_NotImplementedError(const char *msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } + +#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK +NORETURN void mp_raise_recursion_depth(void) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, + MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); +} +#endif diff --git a/py/runtime.h b/py/runtime.h index a8b6312ffe..9e860df156 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -27,6 +27,7 @@ #define MICROPY_INCLUDED_PY_RUNTIME_H #include "py/mpstate.h" +#include "py/pystack.h" typedef enum { MP_VM_RETURN_NORMAL, @@ -106,8 +107,9 @@ mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, size_t n_kw, const mp_obj_t *args); // Call function and catch/dump exception - for Python callbacks from C code -void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg); -void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); +// (return MP_OBJ_NULL in case of exception). +mp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg); +mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2); typedef struct _mp_call_args_t { mp_obj_t fun; @@ -130,6 +132,7 @@ mp_obj_t mp_load_attr(mp_obj_t base, qstr attr); void mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest); void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest); void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest); +void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc); void mp_load_super_method(qstr attr, mp_obj_t *dest); void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val); @@ -155,8 +158,7 @@ NORETURN void mp_raise_RuntimeError(const char *msg); NORETURN void mp_raise_ImportError(const char *msg); NORETURN void mp_raise_IndexError(const char *msg); NORETURN void mp_raise_OSError(int errno_); -NORETURN void mp_raise_NotImplementedError(const char *msg); -NORETURN void mp_exc_recursion_depth(void); +NORETURN void mp_raise_recursion_depth(void); #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG #undef mp_check_self diff --git a/py/runtime0.h b/py/runtime0.h index 4709430fb4..16434b315a 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -133,6 +133,10 @@ typedef enum { #endif , + // The runtime will convert MP_BINARY_OP_IN to this operator with swapped args. + // A type should implement this containment operator instead of MP_BINARY_OP_IN. + MP_BINARY_OP_CONTAINS, + MP_BINARY_OP_NUM_RUNTIME, // These 2 are not supported by the runtime and must be synthesised by the emitter @@ -162,8 +166,8 @@ typedef enum { MP_F_BUILD_MAP, MP_F_STORE_MAP, #if MICROPY_PY_BUILTINS_SET - MP_F_BUILD_SET, MP_F_STORE_SET, + MP_F_BUILD_SET, #endif MP_F_MAKE_FUNCTION_FROM_RAW_CODE, MP_F_NATIVE_CALL_FUNCTION_N_KW, diff --git a/py/runtime_utils.c b/py/runtime_utils.c index bcf3cbf7b6..fd3f071113 100644 --- a/py/runtime_utils.c +++ b/py/runtime_utils.c @@ -28,22 +28,26 @@ #include "py/mpconfig.h" #include "py/runtime.h" -MP_NOINLINE void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) { +MP_NOINLINE mp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_call_function_1(fun, arg); + mp_obj_t ret = mp_call_function_1(fun, arg); nlr_pop(); + return ret; } else { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + return MP_OBJ_NULL; } } -void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { +mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_call_function_2(fun, arg1, arg2); + mp_obj_t ret = mp_call_function_2(fun, arg1, arg2); nlr_pop(); + return ret; } else { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + return MP_OBJ_NULL; } } diff --git a/py/smallint.h b/py/smallint.h index 42679a78fb..6a3c75236c 100644 --- a/py/smallint.h +++ b/py/smallint.h @@ -50,10 +50,10 @@ #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D -#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffffffff80000000) >> 1)) -#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffffffff80000000) == 0) +#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffff800000000000) >> 1)) +#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffff800000000000) == 0) // Mask to truncate mp_int_t to positive value -#define MP_SMALL_INT_POSITIVE_MASK ~(0xffffffff80000000 | (0xffffffff80000000 >> 1)) +#define MP_SMALL_INT_POSITIVE_MASK ~(0xffff800000000000 | (0xffff800000000000 >> 1)) #endif diff --git a/py/stackctrl.c b/py/stackctrl.c index b4ec15b0da..46cbefc8c1 100644 --- a/py/stackctrl.c +++ b/py/stackctrl.c @@ -52,13 +52,9 @@ void mp_stack_set_limit(mp_uint_t limit) { MP_STATE_THREAD(stack_limit) = limit; } -void mp_exc_recursion_depth(void) { - mp_raise_RuntimeError("maximum recursion depth exceeded"); -} - void mp_stack_check(void) { if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) { - mp_exc_recursion_depth(); + mp_raise_recursion_depth(); } } diff --git a/py/stream.c b/py/stream.c index 453dee769f..448de41bbb 100644 --- a/py/stream.c +++ b/py/stream.c @@ -32,13 +32,6 @@ #include "py/stream.h" #include "py/runtime.h" -#if MICROPY_STREAMS_NON_BLOCK -#include -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -#define EWOULDBLOCK 140 -#endif -#endif - // This file defines generic Python stream read/write methods which // dispatch to the underlying stream interface of an object. @@ -54,10 +47,9 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in); // be equal to input size). mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode, byte flags) { byte *buf = buf_; - mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); io_func_t io_func; - const mp_stream_p_t *stream_p = s->type->protocol; + const mp_stream_p_t *stream_p = mp_get_stream(stream); if (flags & MP_STREAM_RW_WRITE) { io_func = (io_func_t)stream_p->write; } else { @@ -105,16 +97,7 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { return stream_p; } -mp_obj_t mp_stream_close(mp_obj_t stream) { - // TODO: Still consider using ioctl for close - mp_obj_t dest[2]; - mp_load_method(stream, MP_QSTR_close, dest); - return mp_call_method_n_kw(0, 0, dest); -} - STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); - // What to do if sz < -1? Python docs don't specify this case. // CPython does a readall, but here we silently let negatives through, // and they will cause a MemoryError. @@ -123,6 +106,8 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl return stream_readall(args[0]); } + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); + #if MICROPY_PY_BUILTINS_STR_UNICODE if (stream_p->is_text) { // We need to read sz number of unicode characters. Because we don't have any @@ -241,8 +226,6 @@ STATIC mp_obj_t stream_read1(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj, 1, 2, stream_read1); mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags) { - mp_get_stream_raise(self_in, MP_STREAM_OP_WRITE); - int error; mp_uint_t out_sz = mp_stream_rw(self_in, (void*)buf, len, &error, flags); if (error != 0) { @@ -258,7 +241,7 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte fla } } -// XXX hack +// This is used to adapt a stream object to an mp_print_t interface void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE); } @@ -290,7 +273,6 @@ STATIC mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) { MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method); STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { - mp_get_stream_raise(args[0], MP_STREAM_OP_READ); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); @@ -319,7 +301,7 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto); STATIC mp_obj_t stream_readall(mp_obj_t self_in) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(self_in, MP_STREAM_OP_READ); + const mp_stream_p_t *stream_p = mp_get_stream(self_in); mp_uint_t total_size = 0; vstr_t vstr; @@ -360,7 +342,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { // Unbuffered, inefficient implementation of readline() for raw I/O files. STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); mp_int_t max_size = -1; if (n_args > 1) { @@ -434,9 +416,18 @@ mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) { return MP_OBJ_STOP_ITERATION; } -STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL); +mp_obj_t mp_stream_close(mp_obj_t stream) { + const mp_stream_p_t *stream_p = mp_get_stream(stream); + int error; + mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error); + if (res == MP_STREAM_ERROR) { + mp_raise_OSError(error); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close); +STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { struct mp_stream_seek_t seek_s; // TODO: Could be uint64 seek_s.offset = mp_obj_get_int(args[1]); @@ -450,6 +441,7 @@ STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { mp_raise_OSError(MP_EINVAL); } + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); int error; mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error); if (res == MP_STREAM_ERROR) { @@ -470,7 +462,7 @@ STATIC mp_obj_t stream_tell(mp_obj_t self) { MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_tell_obj, stream_tell); STATIC mp_obj_t stream_flush(mp_obj_t self) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(self, MP_STREAM_OP_IOCTL); + const mp_stream_p_t *stream_p = mp_get_stream(self); int error; mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error); if (res == MP_STREAM_ERROR) { @@ -481,8 +473,6 @@ STATIC mp_obj_t stream_flush(mp_obj_t self) { MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_flush_obj, stream_flush); STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL); - mp_buffer_info_t bufinfo; uintptr_t val = 0; if (n_args > 2) { @@ -493,6 +483,7 @@ STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) { } } + const mp_stream_p_t *stream_p = mp_get_stream(args[0]); int error; mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error); if (res == MP_STREAM_ERROR) { diff --git a/py/stream.h b/py/stream.h index fbe3d7d859..7b953138c3 100644 --- a/py/stream.h +++ b/py/stream.h @@ -35,7 +35,7 @@ #define MP_STREAM_FLUSH (1) #define MP_STREAM_SEEK (2) #define MP_STREAM_POLL (3) -//#define MP_STREAM_CLOSE (4) // Not yet implemented +#define MP_STREAM_CLOSE (4) #define MP_STREAM_TIMEOUT (5) // Get/set timeout (single op) #define MP_STREAM_GET_OPTS (6) // Get stream options #define MP_STREAM_SET_OPTS (7) // Set stream options @@ -62,6 +62,16 @@ struct mp_stream_seek_t { #define MP_SEEK_CUR (1) #define MP_SEEK_END (2) +// Stream protocol +typedef struct _mp_stream_p_t { + // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values + // are implementation-dependent, but will be exposed to user, e.g. via exception). + mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); + mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode); + mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); + mp_uint_t is_text : 1; // default is bytes, set this for text stream +} mp_stream_p_t; + MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj); @@ -69,6 +79,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_close_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj); @@ -79,6 +90,11 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj); #define MP_STREAM_OP_WRITE (2) #define MP_STREAM_OP_IOCTL (4) +// Object is assumed to have a non-NULL stream protocol with valid r/w/ioctl methods +static inline const mp_stream_p_t *mp_get_stream(mp_const_obj_t self) { + return (const mp_stream_p_t*)((const mp_obj_base_t*)MP_OBJ_TO_PTR(self))->type->protocol; +} + const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags); mp_obj_t mp_stream_close(mp_obj_t stream); @@ -106,7 +122,7 @@ int mp_stream_posix_fsync(mp_obj_t stream); #endif #if MICROPY_STREAMS_NON_BLOCK -#define mp_is_nonblocking_error(errno) ((errno) == EAGAIN || (errno) == EWOULDBLOCK) +#define mp_is_nonblocking_error(errno) ((errno) == MP_EAGAIN || (errno) == MP_EWOULDBLOCK) #else #define mp_is_nonblocking_error(errno) (0) #endif diff --git a/py/unicode.c b/py/unicode.c index 140b7ba712..935dc9012e 100644 --- a/py/unicode.c +++ b/py/unicode.c @@ -67,9 +67,9 @@ STATIC const uint8_t attr[] = { AT_LO, AT_LO, AT_LO, AT_PR, AT_PR, AT_PR, AT_PR, 0 }; -// TODO: Rename to str_get_char -unichar utf8_get_char(const byte *s) { #if MICROPY_PY_BUILTINS_STR_UNICODE + +unichar utf8_get_char(const byte *s) { unichar ord = *s++; if (!UTF8_IS_NONASCII(ord)) return ord; ord &= 0x7F; @@ -80,22 +80,14 @@ unichar utf8_get_char(const byte *s) { ord = (ord << 6) | (*s++ & 0x3F); } return ord; -#else - return *s; -#endif } -// TODO: Rename to str_next_char const byte *utf8_next_char(const byte *s) { -#if MICROPY_PY_BUILTINS_STR_UNICODE ++s; while (UTF8_IS_CONT(*s)) { ++s; } return s; -#else - return s + 1; -#endif } mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr) { @@ -109,21 +101,18 @@ mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr) { return i; } -// TODO: Rename to str_charlen -mp_uint_t unichar_charlen(const char *str, mp_uint_t len) { -#if MICROPY_PY_BUILTINS_STR_UNICODE - mp_uint_t charlen = 0; - for (const char *top = str + len; str < top; ++str) { +size_t utf8_charlen(const byte *str, size_t len) { + size_t charlen = 0; + for (const byte *top = str + len; str < top; ++str) { if (!UTF8_IS_CONT(*str)) { ++charlen; } } return charlen; -#else - return len; -#endif } +#endif + // Be aware: These unichar_is* functions are actually ASCII-only! bool unichar_isspace(unichar c) { return c < 128 && (attr[c] & FL_SPACE) != 0; @@ -183,6 +172,8 @@ mp_uint_t unichar_xdigit_value(unichar c) { return n; } +#if MICROPY_PY_BUILTINS_STR_UNICODE + bool utf8_check(const byte *p, size_t len) { uint8_t need = 0; const byte *end = p + len; @@ -210,3 +201,5 @@ bool utf8_check(const byte *p, size_t len) { } return need == 0; // no pending fragments allowed } + +#endif diff --git a/py/vm.c b/py/vm.c index 564200037a..498ecb491d 100644 --- a/py/vm.c +++ b/py/vm.c @@ -48,14 +48,6 @@ // top element. // Exception stack also grows up, top element is also pointed at. -// Exception stack unwind reasons (WHY_* in CPython-speak) -// TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds -// left to do encoded in the JUMP number -typedef enum { - UNWIND_RETURN = 1, - UNWIND_JUMP, -} mp_unwind_reason_t; - #define DECODE_UINT \ mp_uint_t unum = 0; \ do { \ @@ -144,7 +136,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp #define ENTRY(op) entry_##op #define ENTRY_DEFAULT entry_default #else - #define DISPATCH() break + #define DISPATCH() goto dispatch_loop #define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check #define ENTRY(op) case op #define ENTRY_DEFAULT default @@ -344,7 +336,7 @@ dispatch_loop: MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); - if (mp_obj_get_type(top)->attr == mp_obj_instance_attr) { + if (mp_obj_is_instance_type(mp_obj_get_type(top))) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); mp_uint_t x = *ip; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); @@ -442,7 +434,7 @@ dispatch_loop: MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); - if (mp_obj_get_type(top)->attr == mp_obj_instance_attr && sp[-1] != MP_OBJ_NULL) { + if (mp_obj_is_instance_type(mp_obj_get_type(top)) && sp[-1] != MP_OBJ_NULL) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(top); mp_uint_t x = *ip; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); @@ -613,29 +605,18 @@ dispatch_loop: mp_call_method_n_kw(3, 0, sp); SET_TOP(mp_const_none); } else if (MP_OBJ_IS_SMALL_INT(TOP())) { - mp_int_t cause_val = MP_OBJ_SMALL_INT_VALUE(TOP()); - if (cause_val == UNWIND_RETURN) { - // stack: (..., __exit__, ctx_mgr, ret_val, UNWIND_RETURN) - mp_obj_t ret_val = sp[-1]; - sp[-1] = mp_const_none; - sp[0] = mp_const_none; - sp[1] = mp_const_none; - mp_call_method_n_kw(3, 0, sp - 3); - sp[-3] = ret_val; - sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN); - } else { - assert(cause_val == UNWIND_JUMP); - // stack: (..., __exit__, ctx_mgr, dest_ip, num_exc, UNWIND_JUMP) - mp_obj_t dest_ip = sp[-2]; - mp_obj_t num_exc = sp[-1]; - sp[-2] = mp_const_none; - sp[-1] = mp_const_none; - sp[0] = mp_const_none; - mp_call_method_n_kw(3, 0, sp - 4); - sp[-4] = dest_ip; - sp[-3] = num_exc; - sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP); - } + // Getting here there are two distinct cases: + // - unwind return, stack: (..., __exit__, ctx_mgr, ret_val, SMALL_INT(-1)) + // - unwind jump, stack: (..., __exit__, ctx_mgr, dest_ip, SMALL_INT(num_exc)) + // For both cases we do exactly the same thing. + mp_obj_t data = sp[-1]; + mp_obj_t cause = sp[0]; + sp[-1] = mp_const_none; + sp[0] = mp_const_none; + sp[1] = mp_const_none; + mp_call_method_n_kw(3, 0, sp - 3); + sp[-3] = data; + sp[-2] = cause; sp -= 2; // we removed (__exit__, ctx_mgr) } else { assert(mp_obj_is_exception_instance(TOP())); @@ -680,10 +661,11 @@ unwind_jump:; // of a "with" block contains the context manager info. // We're going to run "finally" code as a coroutine // (not calling it recursively). Set up a sentinel - // on a stack so it can return back to us when it is + // on the stack so it can return back to us when it is // done (when WITH_CLEANUP or END_FINALLY reached). - PUSH((mp_obj_t)unum); // push number of exception handlers left to unwind - PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP)); // push sentinel + // The sentinel is the number of exception handlers left to + // unwind, which is a non-negative integer. + PUSH(MP_OBJ_NEW_SMALL_INT(unum)); ip = exc_sp->handler; // get exception handler byte code address exc_sp--; // pop exception handler goto dispatch_loop; // run the exception handler @@ -720,11 +702,14 @@ unwind_jump:; } else if (MP_OBJ_IS_SMALL_INT(TOP())) { // We finished "finally" coroutine and now dispatch back // to our caller, based on TOS value - mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP()); - if (reason == UNWIND_RETURN) { + mp_int_t cause = MP_OBJ_SMALL_INT_VALUE(POP()); + if (cause < 0) { + // A negative cause indicates unwind return goto unwind_return; } else { - assert(reason == UNWIND_JUMP); + // Otherwise it's an unwind jump and we must push as a raw + // number the number of exception handlers to unwind + PUSH((mp_obj_t)cause); goto unwind_jump; } } else { @@ -926,18 +911,22 @@ unwind_jump:; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); - if (new_state) { + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + deep_recursion_error: + mp_raise_recursion_depth(); + #endif + } else + #endif + { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } - #if MICROPY_STACKLESS_STRICT - else { - deep_recursion_error: - mp_exc_recursion_depth(); - } - #endif } #endif SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); @@ -963,18 +952,26 @@ unwind_jump:; mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); - m_del(mp_obj_t, out_args.args, out_args.n_alloc); - if (new_state) { + #if !MICROPY_ENABLE_PYSTACK + // Freeing args at this point does not follow a LIFO order so only do it if + // pystack is not enabled. For pystack, they are freed when code_state is. + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); + #endif + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + goto deep_recursion_error; + #endif + } else + #endif + { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } - #if MICROPY_STACKLESS_STRICT - else { - goto deep_recursion_error; - } - #endif } #endif SET_TOP(mp_call_method_n_kw_var(false, unum, sp)); @@ -998,17 +995,21 @@ unwind_jump:; int adjust = (sp[1] == MP_OBJ_NULL) ? 0 : 1; mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust); - if (new_state) { + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + goto deep_recursion_error; + #endif + } else + #endif + { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } - #if MICROPY_STACKLESS_STRICT - else { - goto deep_recursion_error; - } - #endif } #endif SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); @@ -1034,18 +1035,26 @@ unwind_jump:; mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); - m_del(mp_obj_t, out_args.args, out_args.n_alloc); - if (new_state) { + #if !MICROPY_ENABLE_PYSTACK + // Freeing args at this point does not follow a LIFO order so only do it if + // pystack is not enabled. For pystack, they are freed when code_state is. + mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t)); + #endif + #if !MICROPY_ENABLE_PYSTACK + if (new_state == NULL) { + // Couldn't allocate codestate on heap: in the strict case raise + // an exception, otherwise just fall through to stack allocation. + #if MICROPY_STACKLESS_STRICT + goto deep_recursion_error; + #endif + } else + #endif + { new_state->prev = code_state; code_state = new_state; nlr_pop(); goto run_code_state; } - #if MICROPY_STACKLESS_STRICT - else { - goto deep_recursion_error; - } - #endif } #endif SET_TOP(mp_call_method_n_kw_var(true, unum, sp)); @@ -1081,7 +1090,7 @@ unwind_return: // (not calling it recursively). Set up a sentinel // on a stack so it can return back to us when it is // done (when WITH_CLEANUP or END_FINALLY reached). - PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN)); + PUSH(MP_OBJ_NEW_SMALL_INT(-1)); ip = exc_sp->handler; exc_sp--; goto dispatch_loop; @@ -1096,7 +1105,15 @@ unwind_return: if (code_state->prev != NULL) { mp_obj_t res = *sp; mp_globals_set(code_state->old_globals); - code_state = code_state->prev; + mp_code_state_t *new_code_state = code_state->prev; + #if MICROPY_ENABLE_PYSTACK + // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var + // (The latter is implicitly freed when using pystack due to its LIFO nature.) + // The sizeof in the following statement does not include the size of the variable + // part of the struct. This arg is anyway not used if pystack is enabled. + mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); + #endif + code_state = new_code_state; *code_state->sp = res; goto run_code_state; } @@ -1105,7 +1122,7 @@ unwind_return: ENTRY(MP_BC_RAISE_VARARGS): { MARK_EXC_IP_SELECTIVE(); - mp_uint_t unum = *ip++; + mp_uint_t unum = *ip; mp_obj_t obj; if (unum == 2) { mp_warning("exception chaining not supported"); @@ -1126,7 +1143,7 @@ unwind_return: RAISE(obj); } } else { - obj = POP(); + obj = TOP(); } obj = mp_make_raise_obj(obj); RAISE(obj); @@ -1149,6 +1166,7 @@ yield: mp_obj_t send_value = POP(); mp_obj_t t_exc = MP_OBJ_NULL; mp_obj_t ret_value; + code_state->sp = sp; // Save sp because it's needed if mp_resume raises StopIteration if (inject_exc != MP_OBJ_NULL) { t_exc = inject_exc; inject_exc = MP_OBJ_NULL; @@ -1164,8 +1182,7 @@ yield: } else if (ret_kind == MP_VM_RETURN_NORMAL) { // Pop exhausted gen sp--; - // TODO: When ret_value can be MP_OBJ_NULL here?? - if (ret_value == MP_OBJ_NULL || ret_value == MP_OBJ_STOP_ITERATION) { + if (ret_value == MP_OBJ_STOP_ITERATION) { // Optimize StopIteration // TODO: get StopIteration's value PUSH(mp_const_none); @@ -1253,10 +1270,10 @@ yield: } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) { fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP(); DISPATCH(); - } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 7) { + } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP())); DISPATCH(); - } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 36) { + } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) { mp_obj_t rhs = POP(); mp_obj_t lhs = TOP(); SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs)); @@ -1305,11 +1322,12 @@ pending_exception_check: #if MICROPY_PY_THREAD_GIL #if MICROPY_PY_THREAD_GIL_VM_DIVISOR - if (--gil_divisor == 0) { - gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; - #else - { + if (--gil_divisor == 0) #endif + { + #if MICROPY_PY_THREAD_GIL_VM_DIVISOR + gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR; + #endif #if MICROPY_ENABLE_SCHEDULER // can only switch threads if the scheduler is unlocked if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) @@ -1348,7 +1366,8 @@ exception_handler: } else if (*code_state->ip == MP_BC_YIELD_FROM) { // StopIteration inside yield from call means return a value of // yield from, so inject exception's value as yield from's result - *++code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); + // (Instead of stack pop then push we just replace exhausted gen with value) + *code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); code_state->ip++; // yield from is over, move to next instruction goto outer_dispatch_loop; // continue with dispatch loop } @@ -1361,8 +1380,7 @@ unwind_loop: // set file and line number that the exception occurred at // TODO: don't set traceback for exceptions re-raised by END_FINALLY. // But consider how to handle nested exceptions. - // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj) - if (nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) { + if (nlr.ret_val != &mp_const_GeneratorExit_obj) { const byte *ip = code_state->fun_bc->bytecode; ip = mp_decode_uint_skip(ip); // skip n_state ip = mp_decode_uint_skip(ip); // skip n_exc_stack @@ -1438,7 +1456,15 @@ unwind_loop: #if MICROPY_STACKLESS } else if (code_state->prev != NULL) { mp_globals_set(code_state->old_globals); - code_state = code_state->prev; + mp_code_state_t *new_code_state = code_state->prev; + #if MICROPY_ENABLE_PYSTACK + // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var + // (The latter is implicitly freed when using pystack due to its LIFO nature.) + // The sizeof in the following statement does not include the size of the variable + // part of the struct. This arg is anyway not used if pystack is enabled. + mp_nonlocal_free(code_state, sizeof(mp_code_state_t)); + #endif + code_state = new_code_state; size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode); fastn = &code_state->state[n_state - 1]; exc_stack = (mp_exc_stack_t*)(code_state->state + n_state); diff --git a/tests/basics/builtin_abs_intbig.py b/tests/basics/builtin_abs_intbig.py index 3dd5ea89fa..8afb7fc691 100644 --- a/tests/basics/builtin_abs_intbig.py +++ b/tests/basics/builtin_abs_intbig.py @@ -7,3 +7,7 @@ print(abs(-123456789012345678901234567890)) # edge cases for 32 and 64 bit archs (small int overflow when negating) print(abs(-0x3fffffff - 1)) print(abs(-0x3fffffffffffffff - 1)) + +# edge case for nan-boxing with 47-bit small int +i = -0x3fffffffffff +print(abs(i - 1)) diff --git a/tests/basics/builtin_compile.py b/tests/basics/builtin_compile.py index 32c6667d8b..bf272aca15 100644 --- a/tests/basics/builtin_compile.py +++ b/tests/basics/builtin_compile.py @@ -46,3 +46,4 @@ if have_compile(): test() else: print("SKIP") + raise SystemExit diff --git a/tests/basics/builtin_dir.py b/tests/basics/builtin_dir.py index 16e7e669e4..c15a76f4c6 100644 --- a/tests/basics/builtin_dir.py +++ b/tests/basics/builtin_dir.py @@ -17,3 +17,22 @@ foo = Foo() print('__init__' in dir(foo)) print('x' in dir(foo)) +# dir of subclass +class A: + def a(): + pass +class B(A): + def b(): + pass +d = dir(B()) +print(d.count('a'), d.count('b')) + +# dir of class with multiple bases and a common parent +class C(A): + def c(): + pass +class D(B, C): + def d(): + pass +d = dir(D()) +print(d.count('a'), d.count('b'), d.count('c'), d.count('d')) diff --git a/tests/basics/enumerate.py b/tests/basics/builtin_enumerate.py similarity index 60% rename from tests/basics/enumerate.py rename to tests/basics/builtin_enumerate.py index 00595cb0f6..29b1dd46c4 100644 --- a/tests/basics/enumerate.py +++ b/tests/basics/builtin_enumerate.py @@ -8,3 +8,10 @@ print(list(enumerate(range(100)))) print(list(enumerate([1, 2, 3], start=1))) print(list(enumerate(iterable=[1, 2, 3]))) print(list(enumerate(iterable=[1, 2, 3], start=1))) + +# check handling of extra positional args (exercises some logic in mp_arg_parse_all) +# don't print anything because it doesn't error with MICROPY_CPYTHON_COMPAT disabled +try: + enumerate([], 1, 2) +except TypeError: + pass diff --git a/tests/basics/builtin_eval.py b/tests/basics/builtin_eval.py index 8b9d02e61b..9b49a2015f 100644 --- a/tests/basics/builtin_eval.py +++ b/tests/basics/builtin_eval.py @@ -1,5 +1,11 @@ # builtin eval +try: + eval +except NameError: + print("SKIP") + raise SystemExit + eval('1 + 2') eval('1 + 2\n') eval('1 + 2\n\n#comment\n') diff --git a/tests/basics/builtin_eval_error.py b/tests/basics/builtin_eval_error.py index 671eedab65..ef0a32da0f 100644 --- a/tests/basics/builtin_eval_error.py +++ b/tests/basics/builtin_eval_error.py @@ -1,5 +1,11 @@ # test if eval raises SyntaxError +try: + eval +except NameError: + print("SKIP") + raise SystemExit + try: print(eval("[1,,]")) except SyntaxError: diff --git a/tests/basics/builtin_exec.py b/tests/basics/builtin_exec.py index fd4e65c539..2e417a43a5 100644 --- a/tests/basics/builtin_exec.py +++ b/tests/basics/builtin_exec.py @@ -1,3 +1,11 @@ +# test builtin exec + +try: + exec +except NameError: + print("SKIP") + raise SystemExit + print(exec("def foo(): return 42")) print(foo()) diff --git a/tests/basics/filter.py b/tests/basics/builtin_filter.py similarity index 100% rename from tests/basics/filter.py rename to tests/basics/builtin_filter.py diff --git a/tests/basics/getattr1.py b/tests/basics/builtin_getattr.py similarity index 100% rename from tests/basics/getattr1.py rename to tests/basics/builtin_getattr.py diff --git a/tests/basics/hasattr1.py b/tests/basics/builtin_hasattr.py similarity index 70% rename from tests/basics/hasattr1.py rename to tests/basics/builtin_hasattr.py index 118a19e579..c60033b963 100644 --- a/tests/basics/hasattr1.py +++ b/tests/basics/builtin_hasattr.py @@ -21,12 +21,19 @@ class C: def __getattr__(self, attr): if attr == "exists": return attr + elif attr == "raise": + raise Exception(123) raise AttributeError c = C() print(hasattr(c, "exists")) -# TODO -#print(hasattr(c, "doesnt_exist")) +print(hasattr(c, "doesnt_exist")) + +# ensure that non-AttributeError exceptions propagate out of hasattr +try: + hasattr(c, "raise") +except Exception as er: + print(er) try: hasattr(1, b'123') diff --git a/tests/basics/builtin_hash_intbig.py b/tests/basics/builtin_hash_intbig.py index 0092c0f3ad..df51f72abb 100644 --- a/tests/basics/builtin_hash_intbig.py +++ b/tests/basics/builtin_hash_intbig.py @@ -8,3 +8,6 @@ class F: def __hash__(self): return 1 << 70 | 1 print(hash(F()) != 0) + +# this had a particular error with internal integer arithmetic of hash function +print(hash(6699999999999999999999999999999999999999999999999999999999999999999999) != 0) diff --git a/tests/basics/builtin_locals.py b/tests/basics/builtin_locals.py index 3689216ef6..e60759a40e 100644 --- a/tests/basics/builtin_locals.py +++ b/tests/basics/builtin_locals.py @@ -2,3 +2,12 @@ x = 123 print(locals()['x']) + +class A: + y = 1 + def f(self): + pass + + print('x' in locals()) + print(locals()['y']) + print('f' in locals()) diff --git a/tests/basics/map.py b/tests/basics/builtin_map.py similarity index 100% rename from tests/basics/map.py rename to tests/basics/builtin_map.py diff --git a/tests/basics/builtin_pow3.py b/tests/basics/builtin_pow3.py index 293a5acc9a..b9e0b8e046 100644 --- a/tests/basics/builtin_pow3.py +++ b/tests/basics/builtin_pow3.py @@ -7,6 +7,12 @@ except NotImplementedError: print("SKIP") raise SystemExit +# test some edge cases +print(pow(1, 1, 1)) +print(pow(0, 1, 1)) +print(pow(1, 0, 1)) +print(pow(1, 0, 2)) + # 3 arg pow is defined to only work on integers try: print(pow("x", 5, 6)) diff --git a/tests/basics/print.py b/tests/basics/builtin_print.py similarity index 100% rename from tests/basics/print.py rename to tests/basics/builtin_print.py diff --git a/tests/basics/builtin_property.py b/tests/basics/builtin_property.py index 89c3d49364..4b08ee9d3b 100644 --- a/tests/basics/builtin_property.py +++ b/tests/basics/builtin_property.py @@ -105,3 +105,9 @@ class E: # not tested for because the other keyword arguments are not accepted # q = property(fget=lambda self: 21, doc="Half the truth.") print(E().p) + +# a property as an instance member should not be delegated to +class F: + def __init__(self): + self.prop_member = property() +print(type(F().prop_member)) diff --git a/tests/basics/builtin_property_inherit.py b/tests/basics/builtin_property_inherit.py new file mode 100644 index 0000000000..27a0913935 --- /dev/null +++ b/tests/basics/builtin_property_inherit.py @@ -0,0 +1,53 @@ +# test builtin property combined with inheritance +try: + property +except: + print("SKIP") + raise SystemExit + +# test property in a base class works for derived classes +class A: + @property + def x(self): + print('A x') + return 123 +class B(A): + pass +class C(B): + pass +class D: + pass +class E(C, D): + pass +print(A().x) +print(B().x) +print(C().x) +print(E().x) + +# test that we can add a property to base class after creation +class F: + pass +F.foo = property(lambda self: print('foo get')) +class G(F): + pass +F().foo +G().foo + +# should be able to add a property to already-subclassed class because it already has one +F.bar = property(lambda self: print('bar get')) +F().bar +G().bar + +# test case where class (H here) is already subclassed before adding attributes +class H: + pass +class I(H): + pass + +# should be able to add a normal member to already-subclassed class +H.val = 2 +print(I().val) + +# should be able to add a property to the derived class +I.baz = property(lambda self: print('baz get')) +I().baz diff --git a/tests/basics/builtin_range.py b/tests/basics/builtin_range.py index 0e2fabd82e..66226bad16 100644 --- a/tests/basics/builtin_range.py +++ b/tests/basics/builtin_range.py @@ -38,6 +38,9 @@ print(range(1, 100, 5)[15:5:-3]) print(range(100, 1, -5)[5:15:3]) print(range(100, 1, -5)[15:5:-3]) +# for this case uPy gives a different stop value but the listed elements are still correct +print(list(range(7, -2, -4)[2:-2:])) + # zero step try: range(1, 2, 0) diff --git a/tests/basics/builtin_range_binop.py b/tests/basics/builtin_range_binop.py new file mode 100644 index 0000000000..e4e054c276 --- /dev/null +++ b/tests/basics/builtin_range_binop.py @@ -0,0 +1,32 @@ +# test binary operations on range objects; (in)equality only + +# this "feature test" actually tests the implementation but is the best we can do +if range(1) != range(1): + print("SKIP") + raise SystemExit + +# basic (in)equality +print(range(1) == range(1)) +print(range(1) != range(1)) +print(range(1) != range(2)) + +# empty range +print(range(0) == range(0)) +print(range(1, 0) == range(0)) +print(range(1, 4, -1) == range(6, 3)) + +# 1 element range +print(range(1, 4, 10) == range(1, 4, 10)) +print(range(1, 4, 10) == range(1, 4, 20)) +print(range(1, 4, 10) == range(1, 8, 20)) + +# more than 1 element +print(range(0, 3, 2) == range(0, 3, 2)) +print(range(0, 3, 2) == range(0, 4, 2)) +print(range(0, 3, 2) == range(0, 5, 2)) + +# unsupported binary op +try: + range(1) + 10 +except TypeError: + print('TypeError') diff --git a/tests/basics/builtin_round_int.py b/tests/basics/builtin_round_int.py new file mode 100644 index 0000000000..a2017622a7 --- /dev/null +++ b/tests/basics/builtin_round_int.py @@ -0,0 +1,18 @@ +# test round() with integer values and second arg + +# rounding integers is an optional feature so test for it +try: + round(1, -1) +except NotImplementedError: + print('SKIP') + raise SystemExit + +tests = [ + (1, False), (1, True), + (124, -1), (125, -1), (126, -1), + (5, -1), (15, -1), (25, -1), + (12345, 0), (12345, -1), (12345, 1), + (-1234, 0), (-1234, -1), (-1234, 1), +] +for t in tests: + print(round(*t)) diff --git a/tests/basics/builtin_round_intbig.py b/tests/basics/builtin_round_intbig.py new file mode 100644 index 0000000000..adf9d29f2f --- /dev/null +++ b/tests/basics/builtin_round_intbig.py @@ -0,0 +1,17 @@ +# test round() with large integer values and second arg + +# rounding integers is an optional feature so test for it +try: + round(1, -1) +except NotImplementedError: + print('SKIP') + raise SystemExit + +i = 2**70 + +tests = [ + (i, 0), (i, -1), (i, -10), (i, 1), + (-i, 0), (-i, -1), (-i, -10), (-i, 1), +] +for t in tests: + print(round(*t)) diff --git a/tests/basics/setattr1.py b/tests/basics/builtin_setattr.py similarity index 52% rename from tests/basics/setattr1.py rename to tests/basics/builtin_setattr.py index 9693aca819..e4acb14cac 100644 --- a/tests/basics/setattr1.py +++ b/tests/basics/builtin_setattr.py @@ -16,3 +16,10 @@ try: setattr(a, b'var3', 1) except TypeError: print('TypeError') + +# try setattr on a built-in function +try: + setattr(int, 'to_bytes', 1) +except (AttributeError, TypeError): + # uPy raises AttributeError, CPython raises TypeError + print('AttributeError/TypeError') diff --git a/tests/basics/builtin_type.py b/tests/basics/builtin_type.py index 83c45c64b9..c5fb36626c 100644 --- a/tests/basics/builtin_type.py +++ b/tests/basics/builtin_type.py @@ -11,3 +11,21 @@ try: type(1, 2) except TypeError: print('TypeError') + +# second arg should be a tuple +try: + type('abc', None, None) +except TypeError: + print('TypeError') + +# third arg should be a dict +try: + type('abc', (), None) +except TypeError: + print('TypeError') + +# elements of second arg (the bases) should be types +try: + type('abc', (1,), {}) +except TypeError: + print('TypeError') diff --git a/tests/basics/zip.py b/tests/basics/builtin_zip.py similarity index 100% rename from tests/basics/zip.py rename to tests/basics/builtin_zip.py diff --git a/tests/basics/bytes.py b/tests/basics/bytes.py index 1d97e6b16f..0b6b14fa55 100644 --- a/tests/basics/bytes.py +++ b/tests/basics/bytes.py @@ -56,3 +56,9 @@ print(x[0], x[1], x[2], x[3]) print(bytes([128, 255])) # For sequence of unknown len print(bytes(iter([128, 255]))) + +# Shouldn't be able to make bytes with negative length +try: + bytes(-1) +except ValueError: + print('ValueError') diff --git a/tests/basics/class_descriptor.py b/tests/basics/class_descriptor.py index eb88ba7b9c..54f386230f 100644 --- a/tests/basics/class_descriptor.py +++ b/tests/basics/class_descriptor.py @@ -27,8 +27,8 @@ except AttributeError: r = m.Forward if 'Descriptor' in repr(r.__class__): print('SKIP') -else: - print(r) - m.Forward = 'a' - del m.Forward + raise SystemExit +print(r) +m.Forward = 'a' +del m.Forward diff --git a/tests/basics/class_inherit_mul.py b/tests/basics/class_inherit_mul.py index 23476132ba..4a43a7f410 100644 --- a/tests/basics/class_inherit_mul.py +++ b/tests/basics/class_inherit_mul.py @@ -1,3 +1,5 @@ +# test multiple inheritance of user classes + class A: def __init__(self, x): print('A init', x) @@ -30,6 +32,9 @@ class Sub(A, B): def g(self): print(self.x) +print(issubclass(Sub, A)) +print(issubclass(Sub, B)) + o = Sub() print(o.x) o.f() diff --git a/tests/basics/class_super.py b/tests/basics/class_super.py index 5a18017ac6..629b7ddb48 100644 --- a/tests/basics/class_super.py +++ b/tests/basics/class_super.py @@ -41,3 +41,20 @@ except TypeError: print(True) else: print(False) + +# first arg to super must be a type +try: + super(1, 1) +except TypeError: + print('TypeError') + +# store/delete of super attribute not allowed +assert hasattr(super(B, B()), 'foo') +try: + super(B, B()).foo = 1 +except AttributeError: + print('AttributeError') +try: + del super(B, B()).foo +except AttributeError: + print('AttributeError') diff --git a/tests/basics/class_super_multinherit.py b/tests/basics/class_super_multinherit.py new file mode 100644 index 0000000000..642a73ce1a --- /dev/null +++ b/tests/basics/class_super_multinherit.py @@ -0,0 +1,16 @@ +# test super with multiple inheritance + +class A: + def foo(self): + print('A.foo') + +class B: + def foo(self): + print('B.foo') + +class C(A, B): + def foo(self): + print('C.foo') + super().foo() + +C().foo() diff --git a/tests/basics/del_attr.py b/tests/basics/del_attr.py index bec7afb848..8487b97e31 100644 --- a/tests/basics/del_attr.py +++ b/tests/basics/del_attr.py @@ -30,3 +30,10 @@ try: del c.x except AttributeError: print("AttributeError") + +# try to del an attribute of a built-in class +try: + del int.to_bytes +except (AttributeError, TypeError): + # uPy raises AttributeError, CPython raises TypeError + print('AttributeError/TypeError') diff --git a/tests/basics/deque1.py b/tests/basics/deque1.py new file mode 100644 index 0000000000..19966fcb07 --- /dev/null +++ b/tests/basics/deque1.py @@ -0,0 +1,68 @@ +try: + try: + from ucollections import deque + except ImportError: + from collections import deque +except ImportError: + print("SKIP") + raise SystemExit + + +d = deque((), 2) +print(len(d)) +print(bool(d)) + +try: + d.popleft() +except IndexError: + print("IndexError") + +print(d.append(1)) +print(len(d)) +print(bool(d)) +print(d.popleft()) +print(len(d)) + +d.append(2) +print(d.popleft()) + +d.append(3) +d.append(4) +print(len(d)) +print(d.popleft(), d.popleft()) +try: + d.popleft() +except IndexError: + print("IndexError") + +d.append(5) +d.append(6) +d.append(7) +print(len(d)) +print(d.popleft(), d.popleft()) +print(len(d)) +try: + d.popleft() +except IndexError: + print("IndexError") + +# Case where get index wraps around when appending to full deque +d = deque((), 2) +d.append(1) +d.append(2) +d.append(3) +d.append(4) +d.append(5) +print(d.popleft(), d.popleft()) + +# Negative maxlen is not allowed +try: + deque((), -1) +except ValueError: + print("ValueError") + +# Unsupported unary op +try: + ~d +except TypeError: + print("TypeError") diff --git a/tests/basics/deque2.py b/tests/basics/deque2.py new file mode 100644 index 0000000000..22d370e943 --- /dev/null +++ b/tests/basics/deque2.py @@ -0,0 +1,66 @@ +# Tests for deques with "check overflow" flag and other extensions +# wrt to CPython. +try: + try: + from ucollections import deque + except ImportError: + from collections import deque +except ImportError: + print("SKIP") + raise SystemExit + + +# Initial sequence is not supported +try: + deque([1, 2, 3], 10) +except ValueError: + print("ValueError") + +# Not even empty list, only empty tuple +try: + deque([], 10) +except ValueError: + print("ValueError") + +# Only fixed-size deques are supported, so length arg is mandatory +try: + deque(()) +except TypeError: + print("TypeError") + +d = deque((), 2, True) + +try: + d.popleft() +except IndexError: + print("IndexError") + +print(d.append(1)) +print(d.popleft()) + +d.append(2) +print(d.popleft()) + +d.append(3) +d.append(4) +print(d.popleft(), d.popleft()) +try: + d.popleft() +except IndexError as e: + print(repr(e)) + +d.append(5) +d.append(6) +print(len(d)) +try: + d.append(7) +except IndexError as e: + print(repr(e)) +print(len(d)) + +print(d.popleft(), d.popleft()) +print(len(d)) +try: + d.popleft() +except IndexError as e: + print(repr(e)) diff --git a/tests/basics/deque2.py.exp b/tests/basics/deque2.py.exp new file mode 100644 index 0000000000..3df8acf405 --- /dev/null +++ b/tests/basics/deque2.py.exp @@ -0,0 +1,15 @@ +ValueError +ValueError +TypeError +IndexError +None +1 +2 +3 4 +IndexError('empty',) +2 +IndexError('full',) +2 +5 6 +0 +IndexError('empty',) diff --git a/tests/basics/dict_fixed.py b/tests/basics/dict_fixed.py new file mode 100644 index 0000000000..4261a06557 --- /dev/null +++ b/tests/basics/dict_fixed.py @@ -0,0 +1,48 @@ +# test that fixed dictionaries cannot be modified + +try: + import uerrno +except ImportError: + print("SKIP") + raise SystemExit + +# Save a copy of uerrno.errorcode, so we can check later +# that it hasn't been modified. +errorcode_copy = uerrno.errorcode.copy() + +try: + uerrno.errorcode.popitem() +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.pop(0) +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.setdefault(0, 0) +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.update([(1, 2)]) +except TypeError: + print("TypeError") + +try: + del uerrno.errorcode[1] +except TypeError: + print("TypeError") + +try: + uerrno.errorcode[1] = 'foo' +except TypeError: + print("TypeError") + +try: + uerrno.errorcode.clear() +except TypeError: + print("TypeError") + +assert uerrno.errorcode == errorcode_copy diff --git a/tests/basics/dict_fixed.py.exp b/tests/basics/dict_fixed.py.exp new file mode 100644 index 0000000000..ffaeb4085c --- /dev/null +++ b/tests/basics/dict_fixed.py.exp @@ -0,0 +1,7 @@ +TypeError +TypeError +TypeError +TypeError +TypeError +TypeError +TypeError diff --git a/tests/basics/errno1.py b/tests/basics/errno1.py index bbbfac10ca..cef5326b4a 100644 --- a/tests/basics/errno1.py +++ b/tests/basics/errno1.py @@ -18,3 +18,7 @@ print(msg[:7], msg[msg.find(']'):]) # check that unknown errno is still rendered print(str(OSError(9999))) + +# this tests a failed constant lookup in errno +errno = uerrno +print(errno.__name__) diff --git a/tests/basics/errno1.py.exp b/tests/basics/errno1.py.exp index b5dd529e46..b550468985 100644 --- a/tests/basics/errno1.py.exp +++ b/tests/basics/errno1.py.exp @@ -2,3 +2,4 @@ [Errno ] Input/output error [Errno ] ENOBUFS 9999 +uerrno diff --git a/tests/basics/fun_calldblstar.py b/tests/basics/fun_calldblstar.py index 15038b2f58..d4816c5cd3 100644 --- a/tests/basics/fun_calldblstar.py +++ b/tests/basics/fun_calldblstar.py @@ -6,6 +6,11 @@ def f(a, b): f(1, **{'b':2}) f(1, **{'b':val for val in range(1)}) +try: + f(1, **{len:2}) +except TypeError: + print('TypeError') + # test calling a method with keywords given by **dict class A: diff --git a/tests/basics/fun_calldblstar2.py b/tests/basics/fun_calldblstar2.py index cf982ef5b8..8795eaf159 100644 --- a/tests/basics/fun_calldblstar2.py +++ b/tests/basics/fun_calldblstar2.py @@ -1,5 +1,11 @@ # test passing a string object as the key for a keyword argument +try: + exec +except NameError: + print("SKIP") + raise SystemExit + # they key in this dict is a string object and is not interned args = {'thisisaverylongargumentname': 123} diff --git a/tests/basics/fun_error.py b/tests/basics/fun_error.py index 367fe0b7fa..3e79c727b3 100644 --- a/tests/basics/fun_error.py +++ b/tests/basics/fun_error.py @@ -1,31 +1,44 @@ # test errors from bad function calls -def test_exc(code, exc): - try: - exec(code) - print("no exception") - except exc: - print("right exception") - except: - print("wrong exception") - # function doesn't take keyword args -test_exc("[].append(x=1)", TypeError) +try: + [].append(x=1) +except TypeError: + print('TypeError') # function with variable number of positional args given too few -test_exc("round()", TypeError) +try: + round() +except TypeError: + print('TypeError') # function with variable number of positional args given too many -test_exc("round(1, 2, 3)", TypeError) +try: + round(1, 2, 3) +except TypeError: + print('TypeError') # function with fixed number of positional args given wrong number -test_exc("[].append(1, 2)", TypeError) +try: + [].append(1, 2) +except TypeError: + print('TypeError') # function with keyword args given extra positional args -test_exc("[].sort(1)", TypeError) +try: + [].sort(1) +except TypeError: + print('TypeError') # function with keyword args given extra keyword args -test_exc("[].sort(noexist=1)", TypeError) +try: + [].sort(noexist=1) +except TypeError: + print('TypeError') # kw given for positional, but a different positional is missing -test_exc("def f(x, y): pass\nf(x=1)", TypeError) +try: + def f(x, y): pass + f(x=1) +except TypeError: + print('TypeError') diff --git a/tests/basics/fun_error2.py b/tests/basics/fun_error2.py index 2a00396e65..39fd0af144 100644 --- a/tests/basics/fun_error2.py +++ b/tests/basics/fun_error2.py @@ -5,14 +5,8 @@ except: print("SKIP") raise SystemExit -def test_exc(code, exc): - try: - exec(code) - print("no exception") - except exc: - print("right exception") - except: - print("wrong exception") - # function with keyword args not given a specific keyword arg -test_exc("enumerate()", TypeError) +try: + enumerate() +except TypeError: + print('TypeError') diff --git a/tests/basics/fun_name.py b/tests/basics/fun_name.py index 7a84fc3390..a724f41118 100644 --- a/tests/basics/fun_name.py +++ b/tests/basics/fun_name.py @@ -14,3 +14,4 @@ try: print(A().Fun.__name__) except AttributeError: print('SKIP') + raise SystemExit diff --git a/tests/basics/gc1.py b/tests/basics/gc1.py index dcbe0bfcf6..332bf9744c 100644 --- a/tests/basics/gc1.py +++ b/tests/basics/gc1.py @@ -27,3 +27,8 @@ if hasattr(gc, 'threshold'): assert(gc.threshold() == 0) assert(gc.threshold(-1) is None) assert(gc.threshold() == -1) + + # Setting a low threshold should trigger collection at the list alloc + gc.threshold(1) + [[], []] + gc.threshold(-1) diff --git a/tests/basics/gen_yield_from.py b/tests/basics/gen_yield_from.py index 5196b48d2b..4e68aec63b 100644 --- a/tests/basics/gen_yield_from.py +++ b/tests/basics/gen_yield_from.py @@ -40,3 +40,16 @@ def gen6(): g = gen6() print(list(g)) + +# StopIteration from within a Python function, within a native iterator (map), within a yield from +def gen7(x): + if x < 3: + return x + else: + raise StopIteration(444) + +def gen8(): + print((yield from map(gen7, range(100)))) + +g = gen8() +print(list(g)) diff --git a/tests/basics/gen_yield_from_executing.py b/tests/basics/gen_yield_from_executing.py new file mode 100644 index 0000000000..cad0c76957 --- /dev/null +++ b/tests/basics/gen_yield_from_executing.py @@ -0,0 +1,15 @@ +# yielding from an already executing generator is not allowed + +def f(): + yield 1 + # g here is already executing so this will raise an exception + yield from g + +g = f() + +print(next(g)) + +try: + next(g) +except ValueError: + print('ValueError') diff --git a/tests/basics/gen_yield_from_throw3.py b/tests/basics/gen_yield_from_throw3.py index 0f6c7c8429..85b6f71f99 100644 --- a/tests/basics/gen_yield_from_throw3.py +++ b/tests/basics/gen_yield_from_throw3.py @@ -28,3 +28,30 @@ print(g.throw(123)) g = gen() print(next(g)) print(g.throw(ZeroDivisionError)) + +# this user-defined generator doesn't have a throw() method +class Iter2: + def __iter__(self): + return self + + def __next__(self): + return 1 + +def gen2(): + yield from Iter2() + +# the thrown ValueError is not intercepted by the user class +g = gen2() +print(next(g)) +try: + g.throw(ValueError) +except: + print('ValueError') + +# the thrown 123 is not an exception so raises a TypeError +g = gen2() +print(next(g)) +try: + g.throw(123) +except TypeError: + print('TypeError') diff --git a/tests/basics/generator_pend_throw.py b/tests/basics/generator_pend_throw.py new file mode 100644 index 0000000000..f00ff793b6 --- /dev/null +++ b/tests/basics/generator_pend_throw.py @@ -0,0 +1,31 @@ +def gen(): + i = 0 + while 1: + yield i + i += 1 + +g = gen() + +try: + g.pend_throw +except AttributeError: + print("SKIP") + raise SystemExit + + +print(next(g)) +print(next(g)) +g.pend_throw(ValueError()) + +v = None +try: + v = next(g) +except Exception as e: + print("raised", repr(e)) + +print("ret was:", v) + +try: + gen().pend_throw(ValueError()) +except TypeError: + print("TypeError") diff --git a/tests/basics/generator_pend_throw.py.exp b/tests/basics/generator_pend_throw.py.exp new file mode 100644 index 0000000000..ed4d882958 --- /dev/null +++ b/tests/basics/generator_pend_throw.py.exp @@ -0,0 +1,5 @@ +0 +1 +raised ValueError() +ret was: None +TypeError diff --git a/tests/basics/int_big1.py b/tests/basics/int_big1.py index 425bc21b67..40d16c455b 100644 --- a/tests/basics/int_big1.py +++ b/tests/basics/int_big1.py @@ -75,6 +75,10 @@ try: print(int("123456789012345678901234567890abcdef")) except ValueError: print('ValueError'); +try: + print(int("123456789012345678901234567890\x01")) +except ValueError: + print('ValueError'); # test constant integer with more than 255 chars x = 0x84ce72aa8699df436059f052ac51b6398d2511e49631bcb7e71f89c499b9ee425dfbc13a5f6d408471b054f2655617cbbaf7937b7c80cd8865cf02c8487d30d2b0fbd8b2c4e102e16d828374bbc47b93852f212d5043c3ea720f086178ff798cc4f63f787b9c2e419efa033e7644ea7936f54462dc21a6c4580725f7f0e7d1aaaaaaa @@ -86,6 +90,11 @@ x = 1073741823 # small x = -1073741823 # small x = 1073741824 # big x = -1073741824 # big +# for nan-boxing with 47-bit small ints +print(int('0x3fffffffffff', 16)) # small +print(int('-0x3fffffffffff', 16)) # small +print(int('0x400000000000', 16)) # big +print(int('-0x400000000000', 16)) # big # for 64 bit archs x = 4611686018427387903 # small x = -4611686018427387903 # small @@ -95,3 +104,7 @@ x = -4611686018427387904 # big # sys.maxsize is a constant mpz, so test it's compatible with dynamic ones import sys print(sys.maxsize + 1 - 1 == sys.maxsize) + +# test extraction of big int value via mp_obj_get_int_maybe +x = 1 << 70 +print('a' * (x + 4 - x)) diff --git a/tests/basics/int_big_add.py b/tests/basics/int_big_add.py index f0c3336d05..b64b76ff0b 100644 --- a/tests/basics/int_big_add.py +++ b/tests/basics/int_big_add.py @@ -5,6 +5,11 @@ i = 0x3fffffff print(i + i) print(-i + -i) +# 47-bit overflow +i = 0x3fffffffffff +print(i + i) +print(-i + -i) + # 63-bit overflow i = 0x3fffffffffffffff print(i + i) diff --git a/tests/basics/int_big_rshift.py b/tests/basics/int_big_rshift.py index b2fecb36c9..e6e2a66993 100644 --- a/tests/basics/int_big_rshift.py +++ b/tests/basics/int_big_rshift.py @@ -3,5 +3,7 @@ print(i >> 1) print(i >> 1000) # result needs rounding up -print(-(1<<70) >> 80) -print(-0xffffffffffffffff >> 32) +i = -(1 << 70) +print(i >> 80) +i = -0xffffffffffffffff +print(i >> 32) diff --git a/tests/basics/int_big_xor.py b/tests/basics/int_big_xor.py index 318db45e60..cd1d9ae97f 100644 --- a/tests/basics/int_big_xor.py +++ b/tests/basics/int_big_xor.py @@ -19,7 +19,8 @@ print((-a) ^ (1 << 100)) print((-a) ^ (1 << 200)) print((-a) ^ a == 0) print(bool((-a) ^ a)) -print(-1 ^ 0xffffffffffffffff) # carry overflows to higher digit +i = -1 +print(i ^ 0xffffffffffffffff) # carry overflows to higher digit # test + - diff --git a/tests/basics/int_constfolding.py b/tests/basics/int_constfolding.py index 7bb5383785..158897f553 100644 --- a/tests/basics/int_constfolding.py +++ b/tests/basics/int_constfolding.py @@ -29,3 +29,9 @@ print(123 // 7, 123 % 7) print(-123 // 7, -123 % 7) print(123 // -7, 123 % -7) print(-123 // -7, -123 % -7) + +# won't fold so an exception can be raised at runtime +try: + 1 << -1 +except ValueError: + print('ValueError') diff --git a/tests/basics/iter1.py b/tests/basics/iter1.py index 9117dfd2b7..26e9a2ef25 100644 --- a/tests/basics/iter1.py +++ b/tests/basics/iter1.py @@ -68,3 +68,12 @@ except StopIteration: for i in myiter(32): print(i) + +# repeat some of the above tests but use tuple() to walk the iterator (tests mp_iternext) +print(tuple(myiter(5))) +print(tuple(myiter(12))) +print(tuple(myiter(32))) +try: + tuple(myiter(22)) +except TypeError: + print('raised TypeError') diff --git a/tests/basics/lexer.py b/tests/basics/lexer.py index 244de8cb98..181d62db1a 100644 --- a/tests/basics/lexer.py +++ b/tests/basics/lexer.py @@ -1,5 +1,12 @@ # test the lexer +try: + eval + exec +except NameError: + print("SKIP") + raise SystemExit + # __debug__ is a special symbol print(type(__debug__)) diff --git a/tests/basics/memoryerror.py b/tests/basics/memoryerror.py index ba145b7d4e..18053f097a 100644 --- a/tests/basics/memoryerror.py +++ b/tests/basics/memoryerror.py @@ -1,6 +1,13 @@ +# test out-of-memory with malloc l = list(range(1000)) try: 1000000000 * l except MemoryError: print('MemoryError') print(len(l), l[0], l[-1]) + +# test out-of-memory with realloc +try: + [].extend(range(1000000000)) +except MemoryError: + print('MemoryError') diff --git a/tests/basics/memoryerror.py.exp b/tests/basics/memoryerror.py.exp index c41e8c1a6a..3d6c7f0009 100644 --- a/tests/basics/memoryerror.py.exp +++ b/tests/basics/memoryerror.py.exp @@ -1,2 +1,3 @@ MemoryError 1000 0 999 +MemoryError diff --git a/tests/basics/namedtuple_asdict.py b/tests/basics/namedtuple_asdict.py new file mode 100644 index 0000000000..c5681376fd --- /dev/null +++ b/tests/basics/namedtuple_asdict.py @@ -0,0 +1,20 @@ +try: + try: + from collections import namedtuple + except ImportError: + from ucollections import namedtuple +except ImportError: + print("SKIP") + raise SystemExit + +t = namedtuple("Tup", ["baz", "foo", "bar"])(3, 2, 5) + +try: + t._asdict +except AttributeError: + print("SKIP") + raise SystemExit + +d = t._asdict() +print(list(d.keys())) +print(list(d.values())) diff --git a/tests/basics/op_error.py b/tests/basics/op_error.py index b30b5f0a35..7b4f896e14 100644 --- a/tests/basics/op_error.py +++ b/tests/basics/op_error.py @@ -1,44 +1,89 @@ # test errors from bad operations (unary, binary, etc) -def test_exc(code, exc): - try: - exec(code) - print("no exception") - except exc: - print("right exception") - except: - print("wrong exception") - # unsupported unary operators -test_exc("~None", TypeError) -test_exc("~''", TypeError) -test_exc("~[]", TypeError) -test_exc("~bytearray()", TypeError) +try: + ~None +except TypeError: + print('TypeError') +try: + ~'' +except TypeError: + print('TypeError') +try: + ~[] +except TypeError: + print('TypeError') +try: + ~bytearray() +except TypeError: + print('TypeError') # unsupported binary operators -test_exc("False in True", TypeError) -test_exc("1 * {}", TypeError) -test_exc("1 in 1", TypeError) -test_exc("bytearray() // 2", TypeError) +try: + False in True +except TypeError: + print('TypeError') +try: + 1 * {} +except TypeError: + print('TypeError') +try: + 1 in 1 +except TypeError: + print('TypeError') +try: + bytearray() // 2 +except TypeError: + print('TypeError') # object with buffer protocol needed on rhs -test_exc("bytearray(1) + 1", TypeError) +try: + bytearray(1) + 1 +except TypeError: + print('TypeError') # unsupported subscription -test_exc("1[0]", TypeError) -test_exc("1[0] = 1", TypeError) -test_exc("''['']", TypeError) -test_exc("'a'[0] = 1", TypeError) -test_exc("del 1[0]", TypeError) +try: + 1[0] +except TypeError: + print('TypeError') +try: + 1[0] = 1 +except TypeError: + print('TypeError') +try: + ''[''] +except TypeError: + print('TypeError') +try: + 'a'[0] = 1 +except TypeError: + print('TypeError') +try: + del 1[0] +except TypeError: + print('TypeError') # not callable -test_exc("1()", TypeError) +try: + 1() +except TypeError: + print('TypeError') # not an iterator -test_exc("next(1)", TypeError) +try: + next(1) +except TypeError: + print('TypeError') # must be an exception type -test_exc("raise 1", TypeError) +try: + raise 1 +except TypeError: + print('TypeError') # no such name in import -test_exc("from sys import youcannotimportmebecauseidontexist", ImportError) +try: + from sys import youcannotimportmebecauseidontexist +except ImportError: + print('ImportError') diff --git a/tests/basics/op_error_intbig.py b/tests/basics/op_error_intbig.py index 432c05a9fe..7def75b0c6 100644 --- a/tests/basics/op_error_intbig.py +++ b/tests/basics/op_error_intbig.py @@ -10,4 +10,7 @@ def test_exc(code, exc): print("wrong exception") # object with buffer protocol needed on rhs -test_exc("(1 << 70) in 1", TypeError) +try: + (1 << 70) in 1 +except TypeError: + print('TypeError') diff --git a/tests/basics/op_error_memoryview.py b/tests/basics/op_error_memoryview.py index 8d4403f777..233f7f9ab7 100644 --- a/tests/basics/op_error_memoryview.py +++ b/tests/basics/op_error_memoryview.py @@ -5,14 +5,9 @@ except: print("SKIP") raise SystemExit -def test_exc(code, exc): - try: - exec(code) - print("no exception") - except exc: - print("right exception") - except: - print("wrong exception") - # unsupported binary operators -test_exc("m = memoryview(bytearray())\nm += bytearray()", TypeError) +try: + m = memoryview(bytearray()) + m += bytearray() +except TypeError: + print('TypeError') diff --git a/tests/basics/python34.py b/tests/basics/python34.py index d5cc59ad6c..36531f11cf 100644 --- a/tests/basics/python34.py +++ b/tests/basics/python34.py @@ -1,5 +1,11 @@ # tests that differ when running under Python 3.4 vs 3.5/3.6 +try: + exec +except NameError: + print("SKIP") + raise SystemExit + # from basics/fun_kwvarargs.py # test evaluation order of arguments (in 3.4 it's backwards, 3.5 it's fixed) def f4(*vargs, **kwargs): diff --git a/tests/basics/python36.py b/tests/basics/python36.py new file mode 100644 index 0000000000..20ecd9227d --- /dev/null +++ b/tests/basics/python36.py @@ -0,0 +1,10 @@ +# tests for things that only Python 3.6 supports + +# underscores in numeric literals +print(100_000) +print(0b1010_0101) +print(0xff_ff) + +# underscore supported by int constructor +print(int('1_2_3')) +print(int('0o1_2_3', 8)) diff --git a/tests/basics/python36.py.exp b/tests/basics/python36.py.exp new file mode 100644 index 0000000000..4b65daafa1 --- /dev/null +++ b/tests/basics/python36.py.exp @@ -0,0 +1,5 @@ +100000 +165 +65535 +123 +83 diff --git a/tests/basics/set_binop.py b/tests/basics/set_binop.py index bc76533b1f..bf55f87db5 100644 --- a/tests/basics/set_binop.py +++ b/tests/basics/set_binop.py @@ -60,6 +60,12 @@ except TypeError: print('TypeError') # unsupported operator +try: + set('abc') * set('abc') +except TypeError: + print('TypeError') + +# unsupported operator with RHS not a set try: set('abc') * 2 except TypeError: diff --git a/tests/basics/set_isfooset.py b/tests/basics/set_isfooset.py index ce7952cd2c..27dedea00a 100644 --- a/tests/basics/set_isfooset.py +++ b/tests/basics/set_isfooset.py @@ -1,5 +1,6 @@ sets = [set(), {1}, {1, 2, 3}, {3, 4, 5}, {5, 6, 7}] +args = sets + [[1], [1, 2], [1, 2 ,3]] for i in sets: - for j in sets: + for j in args: print(i.issubset(j)) print(i.issuperset(j)) diff --git a/tests/basics/special_methods2.py b/tests/basics/special_methods2.py index ba7cf27cda..c21618e93d 100644 --- a/tests/basics/special_methods2.py +++ b/tests/basics/special_methods2.py @@ -94,6 +94,9 @@ class Cud(): print("__isub__ called") return self + def __dir__(self): + return ['a', 'b', 'c'] + cud1 = Cud() cud2 = Cud() @@ -112,33 +115,25 @@ cud1 / cud2 cud2 // cud1 cud1 += cud2 cud1 -= cud2 +cud1 % 2 +cud1 ** 2 +cud1 | cud2 +cud1 & cud2 +cud1 ^ cud2 +cud1 << 1 +cud1 >> 1 + +# test that dir() delegates to __dir__ special method +print(dir(cud1)) + +# test that dir() does not delegate to __dir__ for the type +print('a' in dir(Cud)) # TODO: the following operations are not supported on every ports # # ne is not supported, !(eq) is called instead #cud1 != cud2 # -# binary and is not supported -# cud1 & cud2 -# -# binary lshift is not supported -# cud1<<1 -# -# modulus is not supported -# cud1 % 2 -# -# binary or is not supported -# cud1 | cud2 -# -# pow is not supported -# cud1**2 -# -# rshift is not suported -# cud1>>1 -# -# xor is not supported -# cud1^cud2 -# # in the followin test, cpython still calls __eq__ # cud3=cud1 # cud3==cud1 diff --git a/tests/basics/string_compare.py b/tests/basics/string_compare.py index f011ed3630..6515809b36 100644 --- a/tests/basics/string_compare.py +++ b/tests/basics/string_compare.py @@ -53,3 +53,6 @@ print("1/" <= "1") # that does have a hash, but the lengths of the two strings are different import sys print(sys.version == 'a long string that has a hash') + +# this special string would have a hash of 0 but is incremented to 1 +print('Q+?' == 'Q' + '+?') diff --git a/tests/basics/subclass_native_call.py b/tests/basics/subclass_native_call.py new file mode 100644 index 0000000000..c645575225 --- /dev/null +++ b/tests/basics/subclass_native_call.py @@ -0,0 +1,30 @@ +# test calling a subclass of a native class that supports calling + +# For this test we need a native class that can be subclassed (has make_new) +# and is callable (has call). The only one available is machine.Signal, which +# in turns needs PinBase. +try: + import umachine as machine +except ImportError: + import machine +try: + machine.PinBase + machine.Signal +except AttributeError: + print("SKIP") + raise SystemExit + +class Pin(machine.PinBase): + #def __init__(self): + # self.v = 0 + + def value(self, v=None): + return 42 + +class MySignal(machine.Signal): + pass + +s = MySignal(Pin()) + +# apply call to the subclass, which should call the native base +print(s()) diff --git a/tests/basics/subclass_native_call.py.exp b/tests/basics/subclass_native_call.py.exp new file mode 100644 index 0000000000..d81cc0710e --- /dev/null +++ b/tests/basics/subclass_native_call.py.exp @@ -0,0 +1 @@ +42 diff --git a/tests/basics/subclass_native_containment.py b/tests/basics/subclass_native_containment.py new file mode 100644 index 0000000000..7400f7583e --- /dev/null +++ b/tests/basics/subclass_native_containment.py @@ -0,0 +1,22 @@ +# test containment operator on subclass of a native type + +class mylist(list): + pass + +class mydict(dict): + pass + +class mybytes(bytes): + pass + +l = mylist([1, 2, 3]) +print(0 in l) +print(1 in l) + +d = mydict({1:1, 2:2}) +print(0 in l) +print(1 in l) + +b = mybytes(b'1234') +print(0 in b) +print(b'1' in b) diff --git a/tests/basics/subclass_native_init.py b/tests/basics/subclass_native_init.py new file mode 100644 index 0000000000..38d2f23ac3 --- /dev/null +++ b/tests/basics/subclass_native_init.py @@ -0,0 +1,44 @@ +# test subclassing a native type and overriding __init__ + +# overriding list.__init__() +class L(list): + def __init__(self, a, b): + super().__init__([a, b]) +print(L(2, 3)) + +# inherits implicitly from object +class A: + def __init__(self): + print("A.__init__") + super().__init__() +A() + +# inherits explicitly from object +class B(object): + def __init__(self): + print("B.__init__") + super().__init__() +B() + +# multiple inheritance with object explicitly mentioned +class C: + pass +class D(C, object): + def __init__(self): + print('D.__init__') + super().__init__() + def reinit(self): + print('D.foo') + super().__init__() +a = D() +a.__init__() +a.reinit() + +# call __init__() after object is already init'd +class L(list): + def reinit(self): + super().__init__(range(2)) +a = L(range(5)) +print(a) +a.reinit() +print(a) diff --git a/tests/basics/subclass_native_iter.py b/tests/basics/subclass_native_iter.py new file mode 100644 index 0000000000..0f6b369ad1 --- /dev/null +++ b/tests/basics/subclass_native_iter.py @@ -0,0 +1,7 @@ +# test subclassing a native type which can be iterated over + +class mymap(map): + pass + +m = mymap(lambda x: x + 10, range(4)) +print(list(m)) diff --git a/tests/basics/syntaxerror.py b/tests/basics/syntaxerror.py index 4161de017b..8e706c6e23 100644 --- a/tests/basics/syntaxerror.py +++ b/tests/basics/syntaxerror.py @@ -1,5 +1,11 @@ # test syntax errors +try: + exec +except NameError: + print("SKIP") + raise SystemExit + def test_syntax(code): try: exec(code) @@ -29,6 +35,10 @@ test_syntax(" a\n") # malformed integer literal (parser error) test_syntax("123z") +# input doesn't match the grammar (parser error) +test_syntax('1 or 2 or') +test_syntax('{1:') + # can't assign to literals test_syntax("1 = 2") test_syntax("'' = 1") diff --git a/tests/basics/sys_getsizeof.py b/tests/basics/sys_getsizeof.py new file mode 100644 index 0000000000..fe1b403e04 --- /dev/null +++ b/tests/basics/sys_getsizeof.py @@ -0,0 +1,22 @@ +# test sys.getsizeof() function + +import sys +try: + sys.getsizeof +except AttributeError: + print('SKIP') + raise SystemExit + +print(sys.getsizeof([1, 2]) >= 2) +print(sys.getsizeof({1: 2}) >= 2) + +class A: + pass +print(sys.getsizeof(A()) > 0) + +# Only test deque if we have it +try: + from ucollections import deque + assert sys.getsizeof(deque((), 1)) > 0 +except ImportError: + pass diff --git a/tests/basics/try_return.py b/tests/basics/try_return.py new file mode 100644 index 0000000000..492c18d95c --- /dev/null +++ b/tests/basics/try_return.py @@ -0,0 +1,11 @@ +# test use of return with try-except + +def f(l, i): + try: + return l[i] + except IndexError: + print('IndexError') + return -1 + +print(f([1], 0)) +print(f([], 0)) diff --git a/tests/cmdline/cmd_parsetree.py b/tests/cmdline/cmd_parsetree.py index 5f698eeae3..da36c80703 100644 --- a/tests/cmdline/cmd_parsetree.py +++ b/tests/cmdline/cmd_parsetree.py @@ -9,3 +9,4 @@ c = 'a very long str that will not be interned' d = b'bytes' e = b'a very long bytes that will not be interned' f = 123456789012345678901234567890 +g = 123 diff --git a/tests/cmdline/cmd_parsetree.py.exp b/tests/cmdline/cmd_parsetree.py.exp index d9f81d8d4c..12a1bfbe90 100644 --- a/tests/cmdline/cmd_parsetree.py.exp +++ b/tests/cmdline/cmd_parsetree.py.exp @@ -1,5 +1,5 @@ ---------------- -[ 4] rule(1) (n=8) +[ 4] rule(1) (n=9) tok(4) [ 4] rule(22) (n=4) id(i) @@ -25,6 +25,9 @@ [ 11] rule(5) (n=2) id(f) [ 11] literal \.\+ +[ 12] rule(5) (n=2) + id(g) + int(123) ---------------- File cmdline/cmd_parsetree.py, code block '' (descriptor: \.\+, bytecode @\.\+ bytes) Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): @@ -42,6 +45,7 @@ arg names: bc=27 line=9 bc=32 line=10 bc=37 line=11 + bc=42 line=12 00 BUILD_TUPLE 0 02 GET_ITER_STACK 03 FOR_ITER 12 @@ -59,8 +63,10 @@ arg names: 34 STORE_NAME e 37 LOAD_CONST_OBJ \.\+ 39 STORE_NAME f -42 LOAD_CONST_NONE -43 RETURN_VALUE +42 LOAD_CONST_SMALL_INT 123 +45 STORE_NAME g +48 LOAD_CONST_NONE +49 RETURN_VALUE mem: total=\\d\+, current=\\d\+, peak=\\d\+ stack: \\d\+ out of \\d\+ GC: total: \\d\+, used: \\d\+, free: \\d\+ diff --git a/tests/cmdline/repl_autocomplete.py b/tests/cmdline/repl_autocomplete.py index a848cab0f6..27cad428f7 100644 --- a/tests/cmdline/repl_autocomplete.py +++ b/tests/cmdline/repl_autocomplete.py @@ -6,5 +6,4 @@ x = '123' 1, x.isdi () i = str i.lowe ('ABC') -j = None -j.  +None.  diff --git a/tests/cmdline/repl_autocomplete.py.exp b/tests/cmdline/repl_autocomplete.py.exp index dfb998ff6e..75002985e3 100644 --- a/tests/cmdline/repl_autocomplete.py.exp +++ b/tests/cmdline/repl_autocomplete.py.exp @@ -10,6 +10,5 @@ Use \.\+ >>> i = str >>> i.lower('ABC') 'abc' ->>> j = None ->>> j. +>>> None. >>> diff --git a/tests/cpydiff/builtin_next_arg2.py b/tests/cpydiff/builtin_next_arg2.py new file mode 100644 index 0000000000..5df2d6e70f --- /dev/null +++ b/tests/cpydiff/builtin_next_arg2.py @@ -0,0 +1,12 @@ +""" +categories: Modules,builtins +description: Second argument to next() is not implemented +cause: MicroPython is optimised for code space. +workaround: Instead of ``val = next(it, deflt)`` use:: + + try: + val = next(it) + except StopIteration: + val = deflt +""" +print(next(iter(range(0)), 42)) diff --git a/tests/cpydiff/core_function_unpacking.py b/tests/cpydiff/core_function_unpacking.py deleted file mode 100644 index 01d25ee4d2..0000000000 --- a/tests/cpydiff/core_function_unpacking.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -categories: Core,Functions -description: Unpacking function arguments in non-last position isn't detected as an error -cause: Unknown -workaround: The syntax below is invalid, never use it in applications. -""" -print(*(1, 2), 3) diff --git a/tests/cpydiff/types_exception_subclassinit.py b/tests/cpydiff/types_exception_subclassinit.py index 1770946462..39cdaf45b8 100644 --- a/tests/cpydiff/types_exception_subclassinit.py +++ b/tests/cpydiff/types_exception_subclassinit.py @@ -1,8 +1,12 @@ """ categories: Types,Exception -description: Exception.__init__ raises TypeError if overridden and called by subclass -cause: Unknown -workaround: Unknown +description: Exception.__init__ method does not exist. +cause: Subclassing native classes is not fully supported in MicroPython. +workaround: Call using ``super()`` instead:: + + class A(Exception): + def __init__(self): + super().__init__() """ class A(Exception): def __init__(self): diff --git a/tests/cpydiff/types_float_rounding.py b/tests/cpydiff/types_float_rounding.py index 82a149d859..c8d3cfbe88 100644 --- a/tests/cpydiff/types_float_rounding.py +++ b/tests/cpydiff/types_float_rounding.py @@ -5,5 +5,3 @@ cause: Unknown workaround: Unknown """ print('%.1g' % -9.9) -print('%.1e' % 9.99) -print('%.1e' % 0.999) diff --git a/tests/cpydiff/types_int_tobytesfloat.py b/tests/cpydiff/types_int_tobytesfloat.py deleted file mode 100644 index 5d5b980fad..0000000000 --- a/tests/cpydiff/types_int_tobytesfloat.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -categories: Types,int -description: Incorrect error message when passing float into to_bytes -cause: Unknown -workaround: Unknown -""" -try: - int('1').to_bytes(1.0) -except TypeError as e: - print(e) diff --git a/tests/cpydiff/types_str_decodeerror.py b/tests/cpydiff/types_str_decodeerror.py deleted file mode 100644 index 944db98fe2..0000000000 --- a/tests/cpydiff/types_str_decodeerror.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -categories: Types,str -description: UnicodeDecodeError not raised when expected -cause: Unknown -workaround: Unknown -""" -try: - print(repr(str(b"\xa1\x80", 'utf8'))) - print('Should not get here') -except UnicodeDecodeError: - print('UnicodeDecodeError') diff --git a/tests/cpydiff/types_str_ljust_rjust.py b/tests/cpydiff/types_str_ljust_rjust.py index 4985962059..fa3f594c1f 100644 --- a/tests/cpydiff/types_str_ljust_rjust.py +++ b/tests/cpydiff/types_str_ljust_rjust.py @@ -2,6 +2,6 @@ categories: Types,str description: str.ljust() and str.rjust() not implemented cause: MicroPython is highly optimized for memory usage. Easy workarounds available. -workaround: Instead of `s.ljust(10)` use `"%-10s" % s`, instead of `s.rjust(10)` use `"% 10s" % s`. Alternatively, `"{:<10}".format(s)` or `"{:>10}".format(s)`. +workaround: Instead of ``s.ljust(10)`` use ``"%-10s" % s``, instead of ``s.rjust(10)`` use ``"% 10s" % s``. Alternatively, ``"{:<10}".format(s)`` or ``"{:>10}".format(s)``. """ print('abc'.ljust(10)) diff --git a/tests/extmod/framebuf2.py b/tests/extmod/framebuf2.py new file mode 100644 index 0000000000..a313170eb5 --- /dev/null +++ b/tests/extmod/framebuf2.py @@ -0,0 +1,62 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print('%u' % ((buf[(x + y * w) // 4] >> ((x & 3) << 1)) & 3), end='') + print() + print("-->8--") + +w = 8 +h = 5 +buf = bytearray(w * h // 4) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS2_HMSB) + +# fill +fbuf.fill(3) +printbuf() +fbuf.fill(0) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 1) +fbuf.pixel(3, 0, 2) +fbuf.pixel(0, 4, 3) +fbuf.pixel(3, 4, 2) +printbuf() + +# get pixel +print(fbuf.pixel(0, 4), fbuf.pixel(1, 1)) + +# scroll +fbuf.fill(0) +fbuf.pixel(2, 2, 3) +printbuf() +fbuf.scroll(0, 1) +printbuf() +fbuf.scroll(1, 0) +printbuf() +fbuf.scroll(-1, -2) +printbuf() + +w2 = 2 +h2 = 3 +buf2 = bytearray(w2 * h2 // 4) +fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, framebuf.GS2_HMSB) + +# blit +fbuf2.fill(0) +fbuf2.pixel(0, 0, 1) +fbuf2.pixel(0, 2, 2) +fbuf2.pixel(1, 0, 1) +fbuf2.pixel(1, 2, 2) +fbuf.fill(3) +fbuf.blit(fbuf2, 3, 3, 0) +fbuf.blit(fbuf2, -1, -1, 0) +fbuf.blit(fbuf2, 16, 16, 0) +printbuf() diff --git a/tests/extmod/framebuf2.py.exp b/tests/extmod/framebuf2.py.exp new file mode 100644 index 0000000000..c53e518a6e --- /dev/null +++ b/tests/extmod/framebuf2.py.exp @@ -0,0 +1,57 @@ +--8<-- +33333333 +33333333 +33333333 +33333333 +33333333 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00000000 +00000000 +-->8-- +--8<-- +10020000 +00000000 +00000000 +00000000 +30020000 +-->8-- +3 0 +--8<-- +00000000 +00000000 +00300000 +00000000 +00000000 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00300000 +00000000 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00030000 +00000000 +-->8-- +--8<-- +00000000 +00300000 +00000000 +00030000 +00000000 +-->8-- +--8<-- +33333333 +23333333 +33333333 +33311333 +33333333 +-->8-- diff --git a/tests/extmod/framebuf8.py b/tests/extmod/framebuf8.py new file mode 100644 index 0000000000..b6899aae91 --- /dev/null +++ b/tests/extmod/framebuf8.py @@ -0,0 +1,32 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print('%02x' % buf[(x + y * w)], end='') + print() + print("-->8--") + +w = 8 +h = 5 +buf = bytearray(w * h) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS8) + +# fill +fbuf.fill(0x55) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 0x11) +fbuf.pixel(w - 1, 0, 0x22) +fbuf.pixel(0, h - 1, 0x33) +fbuf.pixel(w - 1, h - 1, 0xff) +printbuf() + +# get pixel +print(hex(fbuf.pixel(0, h - 1)), hex(fbuf.pixel(1, 1))) diff --git a/tests/extmod/framebuf8.py.exp b/tests/extmod/framebuf8.py.exp new file mode 100644 index 0000000000..01d8976fec --- /dev/null +++ b/tests/extmod/framebuf8.py.exp @@ -0,0 +1,15 @@ +--8<-- +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +-->8-- +--8<-- +1155555555555522 +5555555555555555 +5555555555555555 +5555555555555555 +33555555555555ff +-->8-- +0x33 0x55 diff --git a/tests/extmod/framebuf_subclass.py b/tests/extmod/framebuf_subclass.py new file mode 100644 index 0000000000..6363c224fb --- /dev/null +++ b/tests/extmod/framebuf_subclass.py @@ -0,0 +1,20 @@ +# test subclassing framebuf.FrameBuffer + +try: + import framebuf +except ImportError: + print('SKIP') + raise SystemExit + +class FB(framebuf.FrameBuffer): + def __init__(self, n): + self.n = n + super().__init__(bytearray(2 * n * n), n, n, framebuf.RGB565) + + def foo(self): + self.hline(0, 2, self.n, 0x0304) + +fb = FB(n=3) +fb.pixel(0, 0, 0x0102) +fb.foo() +print(bytes(fb)) diff --git a/tests/extmod/framebuf_subclass.py.exp b/tests/extmod/framebuf_subclass.py.exp new file mode 100644 index 0000000000..23d53ccc62 --- /dev/null +++ b/tests/extmod/framebuf_subclass.py.exp @@ -0,0 +1 @@ +b'\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x03\x04\x03\x04\x03' diff --git a/tests/extmod/time_ms_us.py b/tests/extmod/time_ms_us.py index 31f07d31ba..135cf1e096 100644 --- a/tests/extmod/time_ms_us.py +++ b/tests/extmod/time_ms_us.py @@ -7,5 +7,16 @@ except AttributeError: utime.sleep_ms(1) utime.sleep_us(1) -print(utime.ticks_diff(utime.ticks_ms(), utime.ticks_ms()) <= 1) -print(utime.ticks_diff(utime.ticks_us(), utime.ticks_us()) <= 500) + +t0 = utime.ticks_ms() +t1 = utime.ticks_ms() +print(0 <= utime.ticks_diff(t1, t0) <= 1) + +t0 = utime.ticks_us() +t1 = utime.ticks_us() +print(0 <= utime.ticks_diff(t1, t0) <= 500) + +# ticks_cpu may not be implemented, at least make sure it doesn't decrease +t0 = utime.ticks_cpu() +t1 = utime.ticks_cpu() +print(utime.ticks_diff(t1, t0) >= 0) diff --git a/tests/extmod/time_ms_us.py.exp b/tests/extmod/time_ms_us.py.exp index dbde422651..b8ca7e7ef0 100644 --- a/tests/extmod/time_ms_us.py.exp +++ b/tests/extmod/time_ms_us.py.exp @@ -1,2 +1,3 @@ True True +True diff --git a/tests/extmod/uctypes_bytearray.py b/tests/extmod/uctypes_bytearray.py index 61c7da271f..77c93c3766 100644 --- a/tests/extmod/uctypes_bytearray.py +++ b/tests/extmod/uctypes_bytearray.py @@ -17,3 +17,6 @@ S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN) print(S.arr) # But not INT8, because value range is different print(type(S.arr2)) + +# convert to buffer +print(bytearray(S)) diff --git a/tests/extmod/uctypes_bytearray.py.exp b/tests/extmod/uctypes_bytearray.py.exp index 294f8a5fa4..7c84edbb6d 100644 --- a/tests/extmod/uctypes_bytearray.py.exp +++ b/tests/extmod/uctypes_bytearray.py.exp @@ -1,2 +1,3 @@ bytearray(b'01') +bytearray(b'0123') diff --git a/tests/extmod/uctypes_byteat.py b/tests/extmod/uctypes_byteat.py new file mode 100644 index 0000000000..ab2535db8f --- /dev/null +++ b/tests/extmod/uctypes_byteat.py @@ -0,0 +1,10 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +data = bytearray(b'01234567') + +print(uctypes.bytes_at(uctypes.addressof(data), 4)) +print(uctypes.bytearray_at(uctypes.addressof(data), 4)) diff --git a/tests/extmod/uctypes_byteat.py.exp b/tests/extmod/uctypes_byteat.py.exp new file mode 100644 index 0000000000..e1ae4d0534 --- /dev/null +++ b/tests/extmod/uctypes_byteat.py.exp @@ -0,0 +1,2 @@ +b'0123' +bytearray(b'0123') diff --git a/tests/extmod/uctypes_error.py b/tests/extmod/uctypes_error.py new file mode 100644 index 0000000000..95ba0fad44 --- /dev/null +++ b/tests/extmod/uctypes_error.py @@ -0,0 +1,37 @@ +# test general errors with uctypes + +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +data = bytearray(b"01234567") + +# del subscr not supported +S = uctypes.struct(uctypes.addressof(data), {}) +try: + del S[0] +except TypeError: + print('TypeError') + +# list is an invalid descriptor +S = uctypes.struct(uctypes.addressof(data), []) +try: + S.x +except TypeError: + print('TypeError') + +# can't access attribute with invalid descriptor +S = uctypes.struct(uctypes.addressof(data), {'x':[]}) +try: + S.x +except TypeError: + print('TypeError') + +# can't assign to aggregate +S = uctypes.struct(uctypes.addressof(data), {'x':(uctypes.ARRAY | 0, uctypes.INT8 | 2)}) +try: + S.x = 1 +except TypeError: + print('TypeError') diff --git a/tests/extmod/uctypes_error.py.exp b/tests/extmod/uctypes_error.py.exp new file mode 100644 index 0000000000..802c260d2b --- /dev/null +++ b/tests/extmod/uctypes_error.py.exp @@ -0,0 +1,4 @@ +TypeError +TypeError +TypeError +TypeError diff --git a/tests/extmod/uctypes_sizeof.py b/tests/extmod/uctypes_sizeof.py index 5a6adb4376..e42e06c924 100644 --- a/tests/extmod/uctypes_sizeof.py +++ b/tests/extmod/uctypes_sizeof.py @@ -40,3 +40,8 @@ assert uctypes.sizeof(S.arr4) == 6 print(uctypes.sizeof(S.sub)) assert uctypes.sizeof(S.sub) == 1 +# invalid descriptor +try: + print(uctypes.sizeof([])) +except TypeError: + print("TypeError") diff --git a/tests/extmod/uctypes_sizeof.py.exp b/tests/extmod/uctypes_sizeof.py.exp index fb74def602..b35b11aa0c 100644 --- a/tests/extmod/uctypes_sizeof.py.exp +++ b/tests/extmod/uctypes_sizeof.py.exp @@ -4,3 +4,4 @@ TypeError 6 1 +TypeError diff --git a/tests/extmod/uctypes_sizeof_float.py b/tests/extmod/uctypes_sizeof_float.py new file mode 100644 index 0000000000..1ba8871bdc --- /dev/null +++ b/tests/extmod/uctypes_sizeof_float.py @@ -0,0 +1,8 @@ +try: + import uctypes +except ImportError: + print("SKIP") + raise SystemExit + +print(uctypes.sizeof({'f':uctypes.FLOAT32})) +print(uctypes.sizeof({'f':uctypes.FLOAT64})) diff --git a/tests/extmod/uctypes_sizeof_float.py.exp b/tests/extmod/uctypes_sizeof_float.py.exp new file mode 100644 index 0000000000..de78180725 --- /dev/null +++ b/tests/extmod/uctypes_sizeof_float.py.exp @@ -0,0 +1,2 @@ +4 +8 diff --git a/tests/extmod/uhashlib_sha256.py b/tests/extmod/uhashlib_sha256.py index 0322c20de4..a793ea4930 100644 --- a/tests/extmod/uhashlib_sha256.py +++ b/tests/extmod/uhashlib_sha256.py @@ -23,6 +23,9 @@ print(h.digest()) print(hashlib.sha256(b"\xff" * 64).digest()) +# 56 bytes is a boundary case in the algorithm +print(hashlib.sha256(b"\xff" * 56).digest()) + sha256 = hashlib.sha256(b'hello') try: sha256.update(u'world') diff --git a/tests/extmod/ujson_dump.py b/tests/extmod/ujson_dump.py new file mode 100644 index 0000000000..b1cb4a9cbc --- /dev/null +++ b/tests/extmod/ujson_dump.py @@ -0,0 +1,30 @@ +try: + from uio import StringIO + import ujson as json +except: + try: + from io import StringIO + import json + except ImportError: + print("SKIP") + raise SystemExit + +s = StringIO() +json.dump(False, s) +print(s.getvalue()) + +s = StringIO() +json.dump({"a": (2, [3, None])}, s) +print(s.getvalue()) + +# dump to a small-int not allowed +try: + json.dump(123, 1) +except (AttributeError, OSError): # CPython and uPy have different errors + print('Exception') + +# dump to an object not allowed +try: + json.dump(123, {}) +except (AttributeError, OSError): # CPython and uPy have different errors + print('Exception') diff --git a/tests/extmod/ujson_dump_iobase.py b/tests/extmod/ujson_dump_iobase.py new file mode 100644 index 0000000000..d30d1b561e --- /dev/null +++ b/tests/extmod/ujson_dump_iobase.py @@ -0,0 +1,32 @@ +# test ujson.dump in combination with uio.IOBase + +try: + import uio as io + import ujson as json +except ImportError: + try: + import io, json + except ImportError: + print('SKIP') + raise SystemExit + +if not hasattr(io, 'IOBase'): + print('SKIP') + raise SystemExit + + +# a user stream that only has the write method +class S(io.IOBase): + def __init__(self): + self.buf = '' + def write(self, buf): + if type(buf) == bytearray: + # uPy passes a bytearray, CPython passes a str + buf = str(buf, 'ascii') + self.buf += buf + + +# dump to the user stream +s = S() +json.dump([123, {}], s) +print(s.buf) diff --git a/tests/extmod/uzlib_decompress.py b/tests/extmod/uzlib_decompress.py index 63247955c9..dd6e4876fa 100644 --- a/tests/extmod/uzlib_decompress.py +++ b/tests/extmod/uzlib_decompress.py @@ -15,7 +15,9 @@ PATTERNS = [ (bytes(range(64)), b'x\x9cc`dbfaec\xe7\xe0\xe4\xe2\xe6\xe1\xe5\xe3\x17\x10\x14\x12\x16\x11\x15\x13\x97\x90\x94\x92\x96\x91\x95\x93WPTRVQUS\xd7\xd0\xd4\xd2\xd6\xd1\xd5\xd370426153\xb7\xb0\xb4\xb2\xb6\xb1\xb5\xb3\x07\x00\xaa\xe0\x07\xe1'), (b'hello', b'x\x01\x01\x05\x00\xfa\xffhello\x06,\x02\x15'), # compression level 0 # adaptive/dynamic huffman tree - (b'13371813150|13764518736|12345678901', b'x\x9c\x05\xc1\x81\x01\x000\x04\x04\xb1\x95\\\x1f\xcfn\x86o\x82d\x06Qq\xc8\x9d\xc5X}I}\x00\x951D>I}\x00\x951D>I}\x00\x951D>I}\x00\x951D', b'x\x9c\x05\xc11\x01\x00\x00\x00\x010\x95\x14py\x84\x12C_\x9bR\x8cV\x8a\xd1J1Z)F\x1fw`\x089'), ] for unpacked, packed in PATTERNS: @@ -41,3 +43,9 @@ try: zlib.decompress(b'abc') except Exception: print("Exception") + +# invalid block type +try: + zlib.decompress(b'\x07', -15) # final-block, block-type=3 (invalid) +except Exception as er: + print('Exception') diff --git a/tests/extmod/vfs_basic.py b/tests/extmod/vfs_basic.py index 4fc67d34b2..fbcc92bade 100644 --- a/tests/extmod/vfs_basic.py +++ b/tests/extmod/vfs_basic.py @@ -1,11 +1,7 @@ # test VFS functionality without any particular filesystem type try: - try: - import uos_vfs as uos - open = uos.vfs_open - except ImportError: - import uos + import uos uos.mount except (ImportError, AttributeError): print("SKIP") diff --git a/tests/extmod/vfs_fat_fileio1.py b/tests/extmod/vfs_fat_fileio1.py index e3afbe872f..4635ca84b5 100644 --- a/tests/extmod/vfs_fat_fileio1.py +++ b/tests/extmod/vfs_fat_fileio1.py @@ -1,10 +1,6 @@ try: import uerrno - try: - import uos_vfs as uos - open = uos.vfs_open - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit @@ -115,3 +111,29 @@ except OSError as e: vfs.remove("foo_file.txt") print(list(vfs.ilistdir())) + +# Here we test that opening a file with the heap locked fails correctly. This +# is a special case because file objects use a finaliser and allocating with a +# finaliser is a different path to normal allocation. It would be better to +# test this in the core tests but there are no core objects that use finaliser. +import micropython +micropython.heap_lock() +try: + vfs.open('x', 'r') +except MemoryError: + print('MemoryError') +micropython.heap_unlock() + +# Here we test that the finaliser is actually called during a garbage collection. +import gc +N = 4 +for i in range(N): + n = 'x%d' % i + f = vfs.open(n, 'w') + f.write(n) + f = None # release f without closing + [0, 1, 2, 3] # use up Python stack so f is really gone +gc.collect() # should finalise all N files by closing them +for i in range(N): + with vfs.open('x%d' % i, 'r') as f: + print(f.read()) diff --git a/tests/extmod/vfs_fat_fileio1.py.exp b/tests/extmod/vfs_fat_fileio1.py.exp index a66f07605c..4eb50402c4 100644 --- a/tests/extmod/vfs_fat_fileio1.py.exp +++ b/tests/extmod/vfs_fat_fileio1.py.exp @@ -10,4 +10,9 @@ e o d True -[('foo_dir', 16384, 0)] +[('foo_dir', 16384, 0, 0)] +MemoryError +x0 +x1 +x2 +x3 diff --git a/tests/extmod/vfs_fat_fileio2.py b/tests/extmod/vfs_fat_fileio2.py index dc109266a3..ab9623ddf8 100644 --- a/tests/extmod/vfs_fat_fileio2.py +++ b/tests/extmod/vfs_fat_fileio2.py @@ -1,10 +1,6 @@ try: import uerrno - try: - import uos_vfs as uos - open = uos.vfs_open - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit diff --git a/tests/extmod/vfs_fat_fileio2.py.exp b/tests/extmod/vfs_fat_fileio2.py.exp index 118dee26b5..2684053641 100644 --- a/tests/extmod/vfs_fat_fileio2.py.exp +++ b/tests/extmod/vfs_fat_fileio2.py.exp @@ -3,9 +3,9 @@ True True b'data in file' True -[('sub_file.txt', 32768, 0), ('file.txt', 32768, 0)] -[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)] -[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)] +[('sub_file.txt', 32768, 0, 11), ('file.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 8)] new text -[('moved-to-root.txt', 32768, 0)] +[('moved-to-root.txt', 32768, 0, 8)] ENOSPC: True diff --git a/tests/extmod/vfs_fat_more.py b/tests/extmod/vfs_fat_more.py index 1d9b1c3dd5..8ddaf49fc2 100644 --- a/tests/extmod/vfs_fat_more.py +++ b/tests/extmod/vfs_fat_more.py @@ -1,10 +1,6 @@ import uerrno try: - try: - import uos_vfs as uos - open = uos.vfs_open - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit @@ -116,3 +112,11 @@ uos.umount('/') print(uos.getcwd()) print(uos.listdir()) print(uos.listdir('sys')) + +# test importing a file from a mounted FS +import sys +sys.path.clear() +sys.path.append('/sys') +with open('sys/test_module.py', 'w') as f: + f.write('print("test_module!")') +import test_module diff --git a/tests/extmod/vfs_fat_more.py.exp b/tests/extmod/vfs_fat_more.py.exp index aaca3cc75e..24429ee095 100644 --- a/tests/extmod/vfs_fat_more.py.exp +++ b/tests/extmod/vfs_fat_more.py.exp @@ -26,3 +26,4 @@ mkdir OSError True / ['sys'] [] +test_module! diff --git a/tests/extmod/vfs_fat_oldproto.py b/tests/extmod/vfs_fat_oldproto.py index 8aa59a98e4..b671f3db2b 100644 --- a/tests/extmod/vfs_fat_oldproto.py +++ b/tests/extmod/vfs_fat_oldproto.py @@ -1,9 +1,6 @@ try: import uerrno - try: - import uos_vfs as uos - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit diff --git a/tests/extmod/vfs_fat_oldproto.py.exp b/tests/extmod/vfs_fat_oldproto.py.exp index ab8338cbba..b974683167 100644 --- a/tests/extmod/vfs_fat_oldproto.py.exp +++ b/tests/extmod/vfs_fat_oldproto.py.exp @@ -1,3 +1,3 @@ -[('file.txt', 32768, 0)] +[('file.txt', 32768, 0, 6)] hello! [] diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index 8af83e17ba..30a94ec4e1 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -1,9 +1,6 @@ try: import uerrno - try: - import uos_vfs as uos - except ImportError: - import uos + import uos except ImportError: print("SKIP") raise SystemExit diff --git a/tests/extmod/vfs_fat_ramdisk.py.exp b/tests/extmod/vfs_fat_ramdisk.py.exp index a3c3470a94..ecae81589a 100644 --- a/tests/extmod/vfs_fat_ramdisk.py.exp +++ b/tests/extmod/vfs_fat_ramdisk.py.exp @@ -4,7 +4,7 @@ label: LABEL TEST statvfs: (512, 512, 16, 16, 16, 0, 0, 0, 0, 255) getcwd: / True -[('foo_file.txt', 32768, 0)] +[('foo_file.txt', 32768, 0, 6)] stat root: (16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) stat file: (32768, 0, 0, 0, 0, 0, 6) True @@ -13,5 +13,5 @@ getcwd: /foo_dir [] True getcwd: / -[(b'foo_file.txt', 32768, 0), (b'foo_dir', 16384, 0)] +[(b'foo_file.txt', 32768, 0, 6), (b'foo_dir', 16384, 0, 0)] ENOENT: True diff --git a/tests/extmod/vfs_userfs.py b/tests/extmod/vfs_userfs.py new file mode 100644 index 0000000000..e913f9748c --- /dev/null +++ b/tests/extmod/vfs_userfs.py @@ -0,0 +1,68 @@ +# test VFS functionality with a user-defined filesystem +# also tests parts of uio.IOBase implementation + +import sys, uio + +try: + uio.IOBase + import uos + uos.mount +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class UserFile(uio.IOBase): + def __init__(self, data): + self.data = data + self.pos = 0 + def read(self): + return self.data + def readinto(self, buf): + n = 0 + while n < len(buf) and self.pos < len(self.data): + buf[n] = self.data[self.pos] + n += 1 + self.pos += 1 + return n + def ioctl(self, req, arg): + print('ioctl', req, arg) + return 0 + + +class UserFS: + def __init__(self, files): + self.files = files + def mount(self, readonly, mksfs): + pass + def umount(self): + pass + def stat(self, path): + print('stat', path) + if path in self.files: + return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0) + raise OSError + def open(self, path, mode): + print('open', path, mode) + return UserFile(self.files[path]) + + +# create and mount a user filesystem +user_files = { + '/data.txt': b"some data in a text file\n", + '/usermod1.py': b"print('in usermod1')\nimport usermod2", + '/usermod2.py': b"print('in usermod2')", +} +uos.mount(UserFS(user_files), '/userfs') + +# open and read a file +f = open('/userfs/data.txt') +print(f.read()) + +# import files from the user filesystem +sys.path.append('/userfs') +import usermod1 + +# unmount and undo path addition +uos.umount('/userfs') +sys.path.pop() diff --git a/tests/extmod/vfs_userfs.py.exp b/tests/extmod/vfs_userfs.py.exp new file mode 100644 index 0000000000..6a4d925b91 --- /dev/null +++ b/tests/extmod/vfs_userfs.py.exp @@ -0,0 +1,12 @@ +open /data.txt r +b'some data in a text file\n' +stat /usermod1 +stat /usermod1.py +open /usermod1.py r +ioctl 4 0 +in usermod1 +stat /usermod2 +stat /usermod2.py +open /usermod2.py r +ioctl 4 0 +in usermod2 diff --git a/tests/float/builtin_float_hash.py b/tests/float/builtin_float_hash.py index ba6b639073..7a7e374010 100644 --- a/tests/float/builtin_float_hash.py +++ b/tests/float/builtin_float_hash.py @@ -3,6 +3,7 @@ # these should hash to an integer with a specific value for val in ( '0.0', + '-0.0', '1.0', '2.0', '-12.0', @@ -15,6 +16,8 @@ for val in ( '0.1', '-0.1', '10.3', + '0.4e3', + '1e16', 'inf', '-inf', 'nan', diff --git a/tests/float/builtin_float_pow.py b/tests/float/builtin_float_pow.py new file mode 100644 index 0000000000..2de1b48176 --- /dev/null +++ b/tests/float/builtin_float_pow.py @@ -0,0 +1,11 @@ +# test builtin pow function with float args + +print(pow(0.0, 0.0)) +print(pow(0, 1.0)) +print(pow(1.0, 1)) +print(pow(2.0, 3.0)) +print(pow(2.0, -4.0)) + +print(pow(0.0, float('inf'))) +print(pow(0.0, float('-inf'))) +print(pow(0.0, float('nan'))) diff --git a/tests/float/float1.py b/tests/float/float1.py index c64f965a7d..54807e5ac9 100644 --- a/tests/float/float1.py +++ b/tests/float/float1.py @@ -36,6 +36,10 @@ try: except ValueError: print("ValueError") +# construct from something with the buffer protocol +print(float(b"1.2")) +print(float(bytearray(b"3.4"))) + # unary operators print(bool(0.0)) print(bool(1.2)) diff --git a/tests/float/float_format.py b/tests/float/float_format.py new file mode 100644 index 0000000000..d43535cf2f --- /dev/null +++ b/tests/float/float_format.py @@ -0,0 +1,19 @@ +# test float formatting + +# general rounding +for val in (116, 1111, 1234, 5010, 11111): + print('%.0f' % val) + print('%.1f' % val) + print('%.3f' % val) + +# make sure rounding is done at the correct precision +for prec in range(8): + print(('%%.%df' % prec) % 6e-5) + +# check certain cases that had a digit value of 10 render as a ":" character +print('%.2e' % float('9' * 51 + 'e-39')) +print('%.2e' % float('9' * 40 + 'e-21')) + +# check a case that would render negative digit values, eg ")" characters +# the string is converted back to a float to check for no illegal characters +float('%.23e' % 1e-80) diff --git a/tests/float/float_parse.py b/tests/float/float_parse.py new file mode 100644 index 0000000000..4b026de1c8 --- /dev/null +++ b/tests/float/float_parse.py @@ -0,0 +1,32 @@ +# test parsing of floats + +inf = float('inf') + +# it shouldn't matter where the decimal point is if the exponent balances the value +print(float('1234') - float('0.1234e4')) +print(float('1.015625') - float('1015625e-6')) + +# very large integer part with a very negative exponent should cancel out +print('%.4e' % float('9' * 60 + 'e-60')) +print('%.4e' % float('9' * 60 + 'e-40')) + +# many fractional digits +print(float('.' + '9' * 70)) +print(float('.' + '9' * 70 + 'e20')) +print(float('.' + '9' * 70 + 'e-50') == float('1e-50')) + +# tiny fraction with large exponent +print(float('.' + '0' * 60 + '1e10') == float('1e-51')) +print(float('.' + '0' * 60 + '9e25') == float('9e-36')) +print(float('.' + '0' * 60 + '9e40') == float('9e-21')) + +# ensure that accuracy is retained when value is close to a subnormal +print(float('1.00000000000000000000e-37')) +print(float('10.0000000000000000000e-38')) +print(float('100.000000000000000000e-39')) + +# very large exponent literal +print(float('1e4294967301')) +print(float('1e-4294967301')) +print(float('1e18446744073709551621')) +print(float('1e-18446744073709551621')) diff --git a/tests/float/float_parse_doubleprec.py b/tests/float/float_parse_doubleprec.py new file mode 100644 index 0000000000..dcc0dd5921 --- /dev/null +++ b/tests/float/float_parse_doubleprec.py @@ -0,0 +1,21 @@ +# test parsing of floats, requiring double-precision + +# very large integer part with a very negative exponent should cancel out +print(float('9' * 400 + 'e-100')) +print(float('9' * 400 + 'e-200')) +print(float('9' * 400 + 'e-400')) + +# many fractional digits +print(float('.' + '9' * 400)) +print(float('.' + '9' * 400 + 'e100')) +print(float('.' + '9' * 400 + 'e-100')) + +# tiny fraction with large exponent +print('%.14e' % float('.' + '0' * 400 + '9e100')) +print('%.14e' % float('.' + '0' * 400 + '9e200')) +print('%.14e' % float('.' + '0' * 400 + '9e400')) + +# ensure that accuracy is retained when value is close to a subnormal +print(float('1.00000000000000000000e-307')) +print(float('10.0000000000000000000e-308')) +print(float('100.000000000000000000e-309')) diff --git a/tests/float/python36.py b/tests/float/python36.py new file mode 100644 index 0000000000..6e8fb1f213 --- /dev/null +++ b/tests/float/python36.py @@ -0,0 +1,10 @@ +# tests for things that only Python 3.6 supports, needing floats + +# underscores in numeric literals +print(1_000.1_8) +print('%.2g' % 1e1_2) + +# underscore supported by int/float constructors +print(float('1_2_3')) +print(float('1_2_3.4')) +print('%.2g' % float('1e1_3')) diff --git a/tests/float/python36.py.exp b/tests/float/python36.py.exp new file mode 100644 index 0000000000..3febfed9a0 --- /dev/null +++ b/tests/float/python36.py.exp @@ -0,0 +1,5 @@ +1000.18 +1e+12 +123.0 +123.4 +1e+13 diff --git a/tests/import/mpy_invalid.py b/tests/import/mpy_invalid.py new file mode 100644 index 0000000000..6a4e116e78 --- /dev/null +++ b/tests/import/mpy_invalid.py @@ -0,0 +1,67 @@ +# test importing of invalid .mpy files + +import sys, uio + +try: + uio.IOBase + import uos + uos.mount +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class UserFile(uio.IOBase): + def __init__(self, data): + self.data = data + self.pos = 0 + def read(self): + return self.data + def readinto(self, buf): + n = 0 + while n < len(buf) and self.pos < len(self.data): + buf[n] = self.data[self.pos] + n += 1 + self.pos += 1 + return n + def ioctl(self, req, arg): + return 0 + + +class UserFS: + def __init__(self, files): + self.files = files + def mount(self, readonly, mksfs): + pass + def umount(self): + pass + def stat(self, path): + if path in self.files: + return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0) + raise OSError + def open(self, path, mode): + return UserFile(self.files[path]) + + +# these are the test .mpy files +user_files = { + '/mod0.mpy': b'', # empty file + '/mod1.mpy': b'M', # too short header + '/mod2.mpy': b'M\x00\x00\x00', # bad version +} + +# create and mount a user filesystem +uos.mount(UserFS(user_files), '/userfs') +sys.path.append('/userfs') + +# import .mpy files from the user filesystem +for i in range(len(user_files)): + mod = 'mod%u' % i + try: + __import__(mod) + except ValueError as er: + print(mod, 'ValueError', er) + +# unmount and undo path addition +uos.umount('/userfs') +sys.path.pop() diff --git a/tests/import/mpy_invalid.py.exp b/tests/import/mpy_invalid.py.exp new file mode 100644 index 0000000000..1727ea1cea --- /dev/null +++ b/tests/import/mpy_invalid.py.exp @@ -0,0 +1,3 @@ +mod0 ValueError incompatible .mpy file +mod1 ValueError incompatible .mpy file +mod2 ValueError incompatible .mpy file diff --git a/tests/io/builtin_print_file.py b/tests/io/builtin_print_file.py new file mode 100644 index 0000000000..d9b8e2a960 --- /dev/null +++ b/tests/io/builtin_print_file.py @@ -0,0 +1,17 @@ +# test builtin print function, using file= argument + +import sys + +try: + sys.stdout +except AttributeError: + print('SKIP') + raise SystemExit + +print(file=sys.stdout) +print('test', file=sys.stdout) + +try: + print(file=1) +except (AttributeError, OSError): # CPython and uPy differ in error message + print('Error') diff --git a/tests/io/bytesio_ext2.py b/tests/io/bytesio_ext2.py index c07ad900c9..8f624fd58c 100644 --- a/tests/io/bytesio_ext2.py +++ b/tests/io/bytesio_ext2.py @@ -10,4 +10,4 @@ except Exception as e: # CPython throws ValueError, but MicroPython has consistent stream # interface, so BytesIO raises the same error as a real file, which # is OSError(EINVAL). - print(repr(e)) + print(type(e), e.args[0] > 0) diff --git a/tests/io/bytesio_ext2.py.exp b/tests/io/bytesio_ext2.py.exp index b52e4978aa..724aaf63a2 100644 --- a/tests/io/bytesio_ext2.py.exp +++ b/tests/io/bytesio_ext2.py.exp @@ -1 +1 @@ -OSError(22,) + True diff --git a/tests/io/iobase.py b/tests/io/iobase.py new file mode 100644 index 0000000000..6f554b00f0 --- /dev/null +++ b/tests/io/iobase.py @@ -0,0 +1,19 @@ +try: + import uio as io +except: + import io + +try: + io.IOBase +except AttributeError: + print('SKIP') + raise SystemExit + + +class MyIO(io.IOBase): + def write(self, buf): + # CPython and uPy pass in different types for buf (str vs bytearray) + print('write', len(buf)) + return len(buf) + +print('test', file=MyIO()) diff --git a/tests/micropython/extreme_exc.py b/tests/micropython/extreme_exc.py new file mode 100644 index 0000000000..b9db964068 --- /dev/null +++ b/tests/micropython/extreme_exc.py @@ -0,0 +1,85 @@ +# test some extreme cases of allocating exceptions and tracebacks + +import micropython + +# Check for stackless build, which can't call functions without +# allocating a frame on the heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + +# some ports need to allocate heap for the emergency exception +try: + micropython.alloc_emergency_exception_buf(256) +except AttributeError: + pass + +def main(): + # create an exception with many args while heap is locked + # should revert to empty tuple for args + micropython.heap_lock() + e = Exception(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + micropython.heap_unlock() + print(repr(e)) + + # create an exception with a long formatted error message while heap is locked + # should use emergency exception buffer and truncate the message + def f(): + pass + micropython.heap_lock() + try: + f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)[:10]) + + # create an exception with a long formatted error message while heap is low + # should use the heap and truncate the message + lst = [] + while 1: + try: + lst = [lst] + except MemoryError: + break + try: + f(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=1) + except Exception as er: + e = er + lst[0] = None + lst = None + print(repr(e)[:10]) + + # raise a deep exception with the heap locked + # should use emergency exception and be unable to resize traceback array + def g(): + g() + micropython.heap_lock() + try: + g() + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)[:13]) + + # create an exception on the heap with some traceback on the heap, but then + # raise it with the heap locked so it can't allocate any more traceback + exc = Exception('my exception') + try: + raise exc + except: + pass + def h(e): + raise e + micropython.heap_lock() + try: + h(exc) + except Exception as er: + e = er + micropython.heap_unlock() + print(repr(e)) + +main() diff --git a/tests/micropython/extreme_exc.py.exp b/tests/micropython/extreme_exc.py.exp new file mode 100644 index 0000000000..956257e4cd --- /dev/null +++ b/tests/micropython/extreme_exc.py.exp @@ -0,0 +1,5 @@ +Exception() +TypeError( +TypeError( +RuntimeError( +Exception('my exception',) diff --git a/tests/micropython/heap_lock.py b/tests/micropython/heap_lock.py index 0f0a70eff1..ca3f5806a8 100644 --- a/tests/micropython/heap_lock.py +++ b/tests/micropython/heap_lock.py @@ -2,13 +2,24 @@ import micropython +l = [] +l2 = list(range(100)) + micropython.heap_lock() +# general allocation on the heap try: print([]) except MemoryError: print('MemoryError') +# expansion of a heap block +try: + l.extend(l2) +except MemoryError: + print('MemoryError') + micropython.heap_unlock() +# check that allocation works after an unlock print([]) diff --git a/tests/micropython/heap_lock.py.exp b/tests/micropython/heap_lock.py.exp index 67b208cfc5..819c326634 100644 --- a/tests/micropython/heap_lock.py.exp +++ b/tests/micropython/heap_lock.py.exp @@ -1,2 +1,3 @@ MemoryError +MemoryError [] diff --git a/tests/micropython/heapalloc.py b/tests/micropython/heapalloc.py index 62f26df6af..f74bb92c85 100644 --- a/tests/micropython/heapalloc.py +++ b/tests/micropython/heapalloc.py @@ -2,6 +2,15 @@ import micropython +# Check for stackless build, which can't call functions without +# allocating a frame on heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + def f1(a): print(a) diff --git a/tests/micropython/heapalloc_exc_raise.py b/tests/micropython/heapalloc_exc_raise.py index d60e14ce5d..fb63a84bf3 100644 --- a/tests/micropython/heapalloc_exc_raise.py +++ b/tests/micropython/heapalloc_exc_raise.py @@ -5,6 +5,7 @@ import micropython e = ValueError("error") def func(): + micropython.heap_lock() try: # This works as is because traceback is not allocated # if not possible (heap is locked, no memory). If heap @@ -16,8 +17,7 @@ def func(): raise e except Exception as e2: print(e2) + micropython.heap_unlock() -micropython.heap_lock() func() print("ok") -micropython.heap_unlock() diff --git a/tests/micropython/heapalloc_iter.py b/tests/micropython/heapalloc_iter.py index 79461f999a..163e172111 100644 --- a/tests/micropython/heapalloc_iter.py +++ b/tests/micropython/heapalloc_iter.py @@ -1,7 +1,8 @@ # test that iterating doesn't use the heap try: + frozenset import array -except ImportError: +except (NameError, ImportError): print("SKIP") raise SystemExit @@ -11,8 +12,10 @@ except (ImportError, AttributeError): heap_lock = heap_unlock = lambda:0 def do_iter(l): + heap_lock() for i in l: print(i) + heap_unlock() def gen_func(): yield 1 @@ -55,7 +58,6 @@ print(sum(t)) heap_unlock() # test iterating over collections with the heap locked -heap_lock() do_iter(b'123') do_iter(ba) do_iter(ar) @@ -66,4 +68,3 @@ do_iter(s) do_iter(fs) do_iter(g1) do_iter(g2) -heap_unlock() diff --git a/tests/micropython/heapalloc_super.py b/tests/micropython/heapalloc_super.py index 1cf5293d2d..a8c23393e4 100644 --- a/tests/micropython/heapalloc_super.py +++ b/tests/micropython/heapalloc_super.py @@ -1,6 +1,15 @@ # test super() operations which don't require allocation import micropython +# Check for stackless build, which can't call functions without +# allocating a frame on heap. +try: + def stackless(): pass + micropython.heap_lock(); stackless(); micropython.heap_unlock() +except RuntimeError: + print("SKIP") + raise SystemExit + class A: def foo(self): print('A foo') diff --git a/tests/micropython/heapalloc_traceback.py b/tests/micropython/heapalloc_traceback.py index f4212b6ce1..813dea4b21 100644 --- a/tests/micropython/heapalloc_traceback.py +++ b/tests/micropython/heapalloc_traceback.py @@ -16,17 +16,17 @@ except: pass def test(): + micropython.heap_lock() global global_exc global_exc.__traceback__ = None try: raise global_exc except StopIteration: print('StopIteration') + micropython.heap_unlock() # call test() with heap allocation disabled -micropython.heap_lock() test() -micropython.heap_unlock() # print the exception that was raised buf = uio.StringIO() diff --git a/tests/micropython/heapalloc_traceback.py.exp b/tests/micropython/heapalloc_traceback.py.exp index 291bbd697c..facd0af137 100644 --- a/tests/micropython/heapalloc_traceback.py.exp +++ b/tests/micropython/heapalloc_traceback.py.exp @@ -1,5 +1,5 @@ StopIteration Traceback (most recent call last): - File , line 22, in test + File , line 23, in test StopIteration: diff --git a/tests/micropython/viper_error.py.exp b/tests/micropython/viper_error.py.exp index 96be5a5902..3a8cb02994 100644 --- a/tests/micropython/viper_error.py.exp +++ b/tests/micropython/viper_error.py.exp @@ -18,8 +18,8 @@ ViperTypeError('must raise an object',) ViperTypeError('unary op __pos__ not implemented',) ViperTypeError('unary op __neg__ not implemented',) ViperTypeError('unary op __invert__ not implemented',) -ViperTypeError('binary op __contains__ not implemented',) +ViperTypeError('binary op not implemented',) +NotImplementedError('native yield',) NotImplementedError('native yield',) -NotImplementedError('native yield from',) NotImplementedError('conversion to object',) NotImplementedError('casting',) diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index 8c2f4184b1..99633416a4 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -124,3 +124,28 @@ try: f.x = 1 except AttributeError: print('AttributeError') + +# can't call a function type (ie make new instances of a function) +try: + type(f)() +except TypeError: + print('TypeError') + +# test when object explicitly listed at not-last position in parent tuple +# this is not compliant with CPython because of illegal MRO +class A: + def foo(self): + print('A.foo') +class B(object, A): + pass +B().foo() + +# can't assign property (or other special accessors) to already-subclassed class +class A: + pass +class B(A): + pass +try: + A.bar = property() +except AttributeError: + print('AttributeError') diff --git a/tests/misc/non_compliant.py.exp b/tests/misc/non_compliant.py.exp index 9c157fd5bd..3f15a14406 100644 --- a/tests/misc/non_compliant.py.exp +++ b/tests/misc/non_compliant.py.exp @@ -18,3 +18,6 @@ b'\x01\x02' b'\x01\x00' NotImplementedError AttributeError +TypeError +A.foo +AttributeError diff --git a/tests/misc/print_exception.py b/tests/misc/print_exception.py index 9ab8e728b9..f120fe1e18 100644 --- a/tests/misc/print_exception.py +++ b/tests/misc/print_exception.py @@ -56,3 +56,12 @@ try: f() except Exception as e: print_exc(e) + +# Test non-stream object passed as output object, only valid for uPy +if hasattr(sys, 'print_exception'): + try: + sys.print_exception(Exception, 1) + had_exception = False + except OSError: + had_exception = True + assert had_exception diff --git a/tests/net_hosted/connect_poll.py b/tests/net_hosted/connect_poll.py new file mode 100644 index 0000000000..ece6aa0da9 --- /dev/null +++ b/tests/net_hosted/connect_poll.py @@ -0,0 +1,32 @@ +# test that socket.connect() has correct polling behaviour before, during and after + +try: + import usocket as socket, uselect as select +except: + import socket, select + + +def test(peer_addr): + s = socket.socket() + poller = select.poll() + poller.register(s) + + # test poll before connect + # note: CPython can return POLLHUP, so use the IN|OUT mask + p = poller.poll(0) + print(len(p), p[0][-1] & (select.POLLIN | select.POLLOUT)) + + s.connect(peer_addr) + + # test poll during connection + print(len(poller.poll(0))) + + # test poll after connection is established + p = poller.poll(1000) + print(len(p), p[0][-1]) + + s.close() + + +if __name__ == "__main__": + test(socket.getaddrinfo('micropython.org', 80)[0][-1]) diff --git a/tests/net_hosted/connect_poll.py.exp b/tests/net_hosted/connect_poll.py.exp new file mode 100644 index 0000000000..cdf520e090 --- /dev/null +++ b/tests/net_hosted/connect_poll.py.exp @@ -0,0 +1,3 @@ +1 4 +1 +1 4 diff --git a/tests/pyb/adc.py b/tests/pyb/adc.py index 362ca326d2..0bd9b9d53a 100644 --- a/tests/pyb/adc.py +++ b/tests/pyb/adc.py @@ -1,33 +1,62 @@ -from pyb import ADC -from pyb import Pin +from pyb import ADC, Timer -pin = Pin('X22', mode=Pin.IN, pull=Pin.PULL_DOWN) -adc = ADC('X22') -print(adc) +adct = ADC(16) # Temperature 930 -> 20C +print(adct) +adcv = ADC(17) # Voltage 1500 -> 3.3V +print(adcv) -# read single sample -val = adc.read() -assert val < 500 +# read single sample; 2.5V-5V is pass range +val = adcv.read() +assert val > 1000 and val < 2000 # timer for read_timed -tim = pyb.Timer(5, freq=500) +tim = Timer(5, freq=500) # read into bytearray -buf = bytearray(50) -adc.read_timed(buf, tim) +buf = bytearray(b'\xff' * 50) +adcv.read_timed(buf, tim) print(len(buf)) for i in buf: - assert i < 500 + assert i > 50 and i < 150 # read into arrays with different element sizes import array -ar = array.array('h', 25 * [0]) -adc.read_timed(ar, tim) -print(len(ar)) -for i in buf: - assert i < 500 -ar = array.array('i', 30 * [0]) -adc.read_timed(ar, tim) -print(len(ar)) -for i in buf: - assert i < 500 +arv = array.array('h', 25 * [0x7fff]) +adcv.read_timed(arv, tim) +print(len(arv)) +for i in arv: + assert i > 1000 and i < 2000 + +arv = array.array('i', 30 * [-1]) +adcv.read_timed(arv, tim) +print(len(arv)) +for i in arv: + assert i > 1000 and i < 2000 + +# Test read_timed_multi +arv = bytearray(b'\xff'*50) +art = bytearray(b'\xff'*50) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 60 and i < 125 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 15 and i < 200 + +arv = array.array('i', 25 * [-1]) +art = array.array('i', 25 * [-1]) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 1000 and i < 2000 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 50 and i < 2000 + +arv = array.array('h', 25 * [0x7fff]) +art = array.array('h', 25 * [0x7fff]) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 1000 and i < 2000 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 50 and i < 2000 diff --git a/tests/pyb/adc.py.exp b/tests/pyb/adc.py.exp index 76f3914b03..1aae16fb01 100644 --- a/tests/pyb/adc.py.exp +++ b/tests/pyb/adc.py.exp @@ -1,4 +1,5 @@ - + + 50 25 30 diff --git a/tests/pyb/adcall.py b/tests/pyb/adcall.py new file mode 100644 index 0000000000..cfe179a97b --- /dev/null +++ b/tests/pyb/adcall.py @@ -0,0 +1,31 @@ +from pyb import Pin, ADCAll + +pins = [Pin.cpu.A0, Pin.cpu.A1, Pin.cpu.A2, Pin.cpu.A3] + +# set pins to IN mode, init ADCAll, then check pins are ANALOG +for p in pins: + p.init(p.IN) +adc = ADCAll(12) +for p in pins: + print(p) + +# set pins to IN mode, init ADCAll with mask, then check some pins are ANALOG +for p in pins: + p.init(p.IN) +adc = ADCAll(12, 0x70003) +for p in pins: + print(p) + +# init all pins to ANALOG +adc = ADCAll(12) +print(adc) + +# read all channels +for c in range(19): + print(type(adc.read_channel(c))) + +# call special reading functions +print(0 < adc.read_core_temp() < 100) +print(0 < adc.read_core_vbat() < 4) +print(0 < adc.read_core_vref() < 2) +print(0 < adc.read_vref() < 4) diff --git a/tests/pyb/adcall.py.exp b/tests/pyb/adcall.py.exp new file mode 100644 index 0000000000..5a85ba770e --- /dev/null +++ b/tests/pyb/adcall.py.exp @@ -0,0 +1,32 @@ +Pin(Pin.cpu.A0, mode=Pin.ANALOG) +Pin(Pin.cpu.A1, mode=Pin.ANALOG) +Pin(Pin.cpu.A2, mode=Pin.ANALOG) +Pin(Pin.cpu.A3, mode=Pin.ANALOG) +Pin(Pin.cpu.A0, mode=Pin.ANALOG) +Pin(Pin.cpu.A1, mode=Pin.ANALOG) +Pin(Pin.cpu.A2, mode=Pin.IN) +Pin(Pin.cpu.A3, mode=Pin.IN) + + + + + + + + + + + + + + + + + + + + +True +True +True +True diff --git a/tests/pyb/can.py b/tests/pyb/can.py index 0fd8c8368d..8a08ea9a65 100644 --- a/tests/pyb/can.py +++ b/tests/pyb/can.py @@ -4,6 +4,8 @@ except ImportError: print('SKIP') raise SystemExit +from array import array +import micropython import pyb # test we can correctly create by id or name @@ -19,15 +21,27 @@ CAN.initfilterbanks(14) can = CAN(1) print(can) +# Test state when de-init'd +print(can.state() == can.STOPPED) + can.init(CAN.LOOPBACK) print(can) print(can.any(0)) +# Test state when freshly created +print(can.state() == can.ERROR_ACTIVE) + +# Test that restart can be called +can.restart() + +# Test info returns a sensible value +print(can.info()) + # Catch all filter can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0)) can.send('abcd', 123, timeout=5000) -print(can.any(0)) +print(can.any(0), can.info()) print(can.recv(0)) can.send('abcd', -1, timeout=5000) @@ -44,6 +58,77 @@ except ValueError: else: print('failed') +# Test that recv can work without allocating memory on the heap + +buf = bytearray(10) +l = [0, 0, 0, memoryview(buf)] +l2 = None + +micropython.heap_lock() + +can.send('', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +can.send('1234', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +can.send('01234567', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +can.send('abc', 42) +l2 = can.recv(0, l) +assert l is l2 +print(l, len(l[3]), buf) + +micropython.heap_unlock() + +# Test that recv can work with different arrays behind the memoryview +can.send('abc', 1) +print(bytes(can.recv(0, [0, 0, 0, memoryview(array('B', range(8)))])[3])) +can.send('def', 1) +print(bytes(can.recv(0, [0, 0, 0, memoryview(array('b', range(8)))])[3])) + +# Test for non-list passed as second arg to recv +can.send('abc', 1) +try: + can.recv(0, 1) +except TypeError: + print('TypeError') + +# Test for too-short-list passed as second arg to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0]) +except ValueError: + print('ValueError') + +# Test for non-memoryview passed as 4th element to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0, 0]) +except TypeError: + print('TypeError') + +# Test for read-only-memoryview passed as 4th element to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0, memoryview(bytes(8))]) +except ValueError: + print('ValueError') + +# Test for bad-typecode-memoryview passed as 4th element to recv +can.send('abc', 1) +try: + can.recv(0, [0, 0, 0, memoryview(array('i', range(8)))]) +except ValueError: + print('ValueError') + del can # Testing extended IDs diff --git a/tests/pyb/can.py.exp b/tests/pyb/can.py.exp index e25a0f406e..687935e7f4 100644 --- a/tests/pyb/can.py.exp +++ b/tests/pyb/can.py.exp @@ -7,14 +7,28 @@ CAN YA CAN YB ValueError YC CAN(1) -CAN(1, CAN.LOOPBACK, extframe=False) +True +CAN(1, CAN.LOOPBACK, extframe=False, auto_restart=False) False True +[0, 0, 0, 0, 0, 0, 0, 0] +True [0, 0, 0, 0, 0, 0, 1, 0] (123, False, 0, b'abcd') (2047, False, 0, b'abcd') (0, False, 0, b'abcd') passed -CAN(1, CAN.LOOPBACK, extframe=True) +[42, False, 0, ] 0 bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +[42, False, 0, ] 4 bytearray(b'1234\x00\x00\x00\x00\x00\x00') +[42, False, 0, ] 8 bytearray(b'01234567\x00\x00') +[42, False, 0, ] 3 bytearray(b'abc34567\x00\x00') +b'abc' +b'def' +TypeError +ValueError +TypeError +ValueError +ValueError +CAN(1, CAN.LOOPBACK, extframe=True, auto_restart=False) passed ('0x8', '0x1c', '0xa', b'ok') ('0x800', '0x1c00', '0xa00', b'ok') diff --git a/tests/pyb/dac.py b/tests/pyb/dac.py index 6f03bbc64d..ca68ec7098 100644 --- a/tests/pyb/dac.py +++ b/tests/pyb/dac.py @@ -12,3 +12,7 @@ dac.write(0) dac.write_timed(bytearray(10), 100, mode=pyb.DAC.NORMAL) pyb.delay(20) dac.write(0) + +# test buffering arg +dac = pyb.DAC(1, buffering=True) +dac.write(0) diff --git a/tests/pyb/dac.py.exp b/tests/pyb/dac.py.exp index ae245f2e61..7ee99652a8 100644 --- a/tests/pyb/dac.py.exp +++ b/tests/pyb/dac.py.exp @@ -1 +1 @@ - +DAC(1, bits=8) diff --git a/tests/pyb/i2c.py b/tests/pyb/i2c.py index a220f8e858..6875e5a5aa 100644 --- a/tests/pyb/i2c.py +++ b/tests/pyb/i2c.py @@ -19,7 +19,8 @@ i2c.deinit() accel_addr = 76 -pyb.Accel() # this will init the bus for us +pyb.Accel() # this will init the MMA for us +i2c.init(I2C.MASTER, baudrate=400000) print(i2c.scan()) print(i2c.is_ready(accel_addr)) diff --git a/tests/pyb/pyb1.py b/tests/pyb/pyb1.py index 184acbdc43..443722ca85 100644 --- a/tests/pyb/pyb1.py +++ b/tests/pyb/pyb1.py @@ -29,8 +29,6 @@ pyb.enable_irq() print(pyb.have_cdc()) -pyb.hid((0, 0, 0, 0)) # won't do anything - pyb.sync() print(len(pyb.unique_id())) diff --git a/tests/pyb/spi.py b/tests/pyb/spi.py index b7a905d78c..88cc975bb6 100644 --- a/tests/pyb/spi.py +++ b/tests/pyb/spi.py @@ -29,3 +29,5 @@ spi.init(SPI.MASTER) spi.send(1, timeout=100) print(spi.recv(1, timeout=100)) print(spi.send_recv(1, timeout=100)) + +spi.deinit() diff --git a/tests/run-tests b/tests/run-tests index bcd2e5dccf..3064f6845a 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -53,7 +53,11 @@ def convert_regex_escapes(line): def run_micropython(pyb, args, test_file, is_special=False): - special_tests = ('micropython/meminfo.py', 'basics/bytes_compare3.py', 'basics/builtin_help.py', 'thread/thread_exc2.py') + special_tests = ( + 'micropython/meminfo.py', 'basics/bytes_compare3.py', + 'basics/builtin_help.py', 'thread/thread_exc2.py', + ) + had_crash = False if pyb is None: # run on PC if test_file.startswith(('cmdline/', 'feature_check/')) or test_file in special_tests: @@ -146,13 +150,14 @@ def run_micropython(pyb, args, test_file, is_special=False): try: output_mupy = pyb.execfile(test_file) except pyboard.PyboardError: + had_crash = True output_mupy = b'CRASH' # canonical form for all ports/platforms is to use \n for end-of-line output_mupy = output_mupy.replace(b'\r\n', b'\n') # don't try to convert the output if we should skip this test - if output_mupy in (b'SKIP\n', b'CRASH'): + if had_crash or output_mupy in (b'SKIP\n', b'CRASH'): return output_mupy if is_special or test_file in special_tests: @@ -229,48 +234,56 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): skip_async = False skip_const = False skip_revops = False + skip_endian = False + has_complex = True + has_coverage = False - # Check if micropython.native is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'native_check.py') - if output == b'CRASH': - skip_native = True + upy_float_precision = 32 - # Check if arbitrary-precision integers are supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'int_big.py') - if output != b'1000000000000000000000000000000000000000000000\n': - skip_int_big = True + # If we're asked to --list-tests, we can't assume that there's a + # connection to target, so we can't run feature checks usefully. + if not (args.list_tests or args.write_exp): + # Check if micropython.native is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'native_check.py') + if output == b'CRASH': + skip_native = True - # Check if set type (and set literals) is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'set_check.py') - if output == b'CRASH': - skip_set_type = True + # Check if arbitrary-precision integers are supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'int_big.py') + if output != b'1000000000000000000000000000000000000000000000\n': + skip_int_big = True - # Check if async/await keywords are supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'async_check.py') - if output == b'CRASH': - skip_async = True + # Check if set type (and set literals) is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'set_check.py') + if output == b'CRASH': + skip_set_type = True - # Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'const.py') - if output == b'CRASH': - skip_const = True + # Check if async/await keywords are supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'async_check.py') + if output == b'CRASH': + skip_async = True - # Check if __rOP__ special methods are supported, and skip such tests if it's not - output = run_feature_check(pyb, args, base_path, 'reverse_ops.py') - if output == b'TypeError\n': - skip_revops = True + # Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'const.py') + if output == b'CRASH': + skip_const = True - # Check if emacs repl is supported, and skip such tests if it's not - t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py') - if not 'True' in str(t, 'ascii'): - skip_tests.add('cmdline/repl_emacs_keys.py') + # Check if __rOP__ special methods are supported, and skip such tests if it's not + output = run_feature_check(pyb, args, base_path, 'reverse_ops.py') + if output == b'TypeError\n': + skip_revops = True - upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py') - upy_float_precision = int(run_feature_check(pyb, args, base_path, 'float.py')) - has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n' - has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n' - cpy_byteorder = subprocess.check_output([CPYTHON3, base_path + '/feature_check/byteorder.py']) - skip_endian = (upy_byteorder != cpy_byteorder) + # Check if emacs repl is supported, and skip such tests if it's not + t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py') + if not 'True' in str(t, 'ascii'): + skip_tests.add('cmdline/repl_emacs_keys.py') + + upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py') + upy_float_precision = int(run_feature_check(pyb, args, base_path, 'float.py')) + has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n' + has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n' + cpy_byteorder = subprocess.check_output([CPYTHON3, base_path + '/feature_check/byteorder.py']) + skip_endian = (upy_byteorder != cpy_byteorder) # Some tests shouldn't be run under Travis CI if os.getenv('TRAVIS') == 'true': @@ -292,6 +305,7 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): if upy_float_precision < 64: skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead skip_tests.add('float/float2int_doubleprec_intbig.py') + skip_tests.add('float/float_parse_doubleprec.py') if not has_complex: skip_tests.add('float/complex1.py') @@ -304,23 +318,20 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): skip_tests.add('cmdline/cmd_parsetree.py') # Some tests shouldn't be run on a PC - if pyb is None: + if args.target == 'unix': # unix build does not have the GIL so can't run thread mutation tests for t in tests: if t.startswith('thread/mutate_'): skip_tests.add(t) # Some tests shouldn't be run on pyboard - if pyb is not None: + if args.target != 'unix': skip_tests.add('basics/exception_chain.py') # warning is not printed skip_tests.add('micropython/meminfo.py') # output is very different to PC output skip_tests.add('extmod/machine_mem.py') # raw memory access not supported if args.target == 'wipy': skip_tests.add('misc/print_exception.py') # requires error reporting full - skip_tests.add('misc/recursion.py') # requires stack checking enabled - skip_tests.add('misc/recursive_data.py') # requires stack checking enabled - skip_tests.add('misc/recursive_iternext.py') # requires stack checking enabled skip_tests.update({'extmod/uctypes_%s.py' % t for t in 'bytearray le native_le ptr_le ptr_native_le sizeof sizeof_native array_assign_le array_assign_native_le'.split()}) # requires uctypes skip_tests.add('extmod/zlibd_decompress.py') # requires zlib skip_tests.add('extmod/uheapq1.py') # uheapq not supported by WiPy @@ -330,6 +341,7 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): skip_tests.add('misc/rge_sm.py') # too large elif args.target == 'minimal': skip_tests.add('basics/class_inplace_op.py') # all special methods not supported + skip_tests.add('basics/subclass_native_init.py')# native subclassing corner cases not support skip_tests.add('misc/rge_sm.py') # too large skip_tests.add('micropython/opt_level.py') # don't assume line numbers are stored @@ -344,7 +356,7 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): # Some tests are known to fail with native emitter # Remove them from the below when they work if args.emit == 'native': - skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_return generator_send'.split()}) # require yield + skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_executing gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_pend_throw generator_return generator_send'.split()}) # require yield skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class globals_del string_join gen_stack_overflow'.split()}) # require yield skip_tests.update({'basics/async_%s.py' % t for t in 'def await await2 for for2 with with2'.split()}) # require yield skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs @@ -370,9 +382,22 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): skip_tests.add('micropython/heapalloc_traceback.py') # because native doesn't have proper traceback info skip_tests.add('micropython/heapalloc_iter.py') # requires generators skip_tests.add('micropython/schedule.py') # native code doesn't check pending events + skip_tests.add('stress/gc_trace.py') # requires yield + skip_tests.add('stress/recursive_gen.py') # requires yield + skip_tests.add('extmod/vfs_userfs.py') # because native doesn't properly handle globals across different modules def run_one_test(test_file): test_file = test_file.replace('\\', '/') + + if args.filters: + # Default verdict is the opposit of the first action + verdict = "include" if args.filters[0][0] == "exclude" else "exclude" + for action, pat in args.filters: + if pat.search(test_file): + verdict = action + if verdict == "exclude": + continue + test_basename = os.path.basename(test_file) test_name = os.path.splitext(test_basename)[0] is_native = test_name.startswith("native_") or test_name.startswith("viper_") @@ -391,6 +416,11 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): skip_it |= skip_const and is_const skip_it |= skip_revops and test_name.startswith("class_reverse_op") + if args.list_tests: + if not skip_it: + print(test_file) + continue + if skip_it: print("skip ", test_file) skipped_tests.append(test_name) @@ -456,6 +486,9 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): test_count.add(1) + if args.list_tests: + return True + if num_threads > 1: pool = ThreadPool(num_threads) pool.map(run_one_test, tests) @@ -475,15 +508,44 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): # all tests succeeded return True + +class append_filter(argparse.Action): + + def __init__(self, option_strings, dest, **kwargs): + super().__init__(option_strings, dest, default=[], **kwargs) + + def __call__(self, parser, args, value, option): + if not hasattr(args, self.dest): + args.filters = [] + if option.startswith(("-e", "--e")): + option = "exclude" + else: + option = "include" + args.filters.append((option, re.compile(value))) + + def main(): - cmd_parser = argparse.ArgumentParser(description='Run tests for MicroPython.') + cmd_parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description='Run and manage tests for MicroPython.', + epilog='''\ +Options -i and -e can be multiple and processed in the order given. Regex +"search" (vs "match") operation is used. An action (include/exclude) of +the last matching regex is used: + run-tests -i async - exclude all, then include tests containg "async" anywhere + run-tests -e '/big.+int' - include all, then exclude by regex + run-tests -e async -i async_foo - include all, exclude async, yet still include async_foo +''') cmd_parser.add_argument('--target', default='unix', help='the target platform') cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard') cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username') cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)') + cmd_parser.add_argument('-e', '--exclude', action=append_filter, metavar='REGEX', dest='filters', help='exclude test by regex on path/name.py') + cmd_parser.add_argument('-i', '--include', action=append_filter, metavar='REGEX', dest='filters', help='include test by regex on path/name.py') cmd_parser.add_argument('--write-exp', action='store_true', help='save .exp files to run tests w/o CPython') + cmd_parser.add_argument('--list-tests', action='store_true', help='list tests instead of running them') cmd_parser.add_argument('--emit', default='bytecode', help='MicroPython emitter to use (bytecode or native)') cmd_parser.add_argument('--heapsize', help='heapsize to use (use default if not specified)') cmd_parser.add_argument('--via-mpy', action='store_true', help='compile .py files to .mpy first') @@ -493,14 +555,13 @@ def main(): cmd_parser.add_argument('files', nargs='*', help='input test files') args = cmd_parser.parse_args() - EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'minimal') - if args.target in EXTERNAL_TARGETS: - args.jobs = 1 + EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'esp32', 'minimal') + if args.target == 'unix' or args.list_tests: + pyb = None + elif args.target in EXTERNAL_TARGETS: import pyboard pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password) pyb.enter_raw_repl() - elif args.target == 'unix': - pyb = None else: raise ValueError('target must be either %s or unix' % ", ".join(EXTERNAL_TARGETS)) @@ -509,14 +570,17 @@ def main(): if args.target == 'pyboard': # run pyboard tests test_dirs = ('basics', 'micropython', 'float', 'misc', 'stress', 'extmod', 'pyb', 'pybnative', 'inlineasm') - elif args.target in ('esp8266', 'minimal'): + elif args.target in ('esp8266', 'esp32', 'minimal'): test_dirs = ('basics', 'micropython', 'float', 'misc', 'extmod') elif args.target == 'wipy': # run WiPy tests test_dirs = ('basics', 'micropython', 'misc', 'extmod', 'wipy') else: # run PC tests - test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc', 'stress', 'unicode', 'extmod', 'unix', 'cmdline') + test_dirs = ( + 'basics', 'micropython', 'float', 'import', 'io', 'misc', + 'stress', 'unicode', 'extmod', 'unix', 'cmdline', + ) else: # run tests from these directories test_dirs = args.test_dirs diff --git a/tests/stress/dict_create_max.py b/tests/stress/dict_create_max.py new file mode 100644 index 0000000000..3c75db20da --- /dev/null +++ b/tests/stress/dict_create_max.py @@ -0,0 +1,13 @@ +# The aim with this test is to hit the maximum resize/rehash size of a dict, +# where there are no more primes in the table of growing allocation sizes. +# This value is 54907 items. + +d = {} +try: + for i in range(54908): + d[i] = i +except MemoryError: + pass + +# Just check the dict still has the first value +print(d[0]) diff --git a/tests/stress/gc_trace.py b/tests/stress/gc_trace.py new file mode 100644 index 0000000000..72dc7b6276 --- /dev/null +++ b/tests/stress/gc_trace.py @@ -0,0 +1,17 @@ +# test that the GC can trace nested objects + +try: + import gc +except ImportError: + print("SKIP") + raise SystemExit + +# test a big shallow object pointing to many unique objects +lst = [[i] for i in range(200)] +gc.collect() +print(lst) + +# test a deep object +lst = [[[[[(i, j, k, l)] for i in range(3)] for j in range(3)] for k in range(3)] for l in range(3)] +gc.collect() +print(lst) diff --git a/tests/misc/recursion.py b/tests/stress/recursion.py similarity index 100% rename from tests/misc/recursion.py rename to tests/stress/recursion.py diff --git a/tests/misc/recursive_data.py b/tests/stress/recursive_data.py similarity index 100% rename from tests/misc/recursive_data.py rename to tests/stress/recursive_data.py diff --git a/tests/misc/recursive_data.py.exp b/tests/stress/recursive_data.py.exp similarity index 100% rename from tests/misc/recursive_data.py.exp rename to tests/stress/recursive_data.py.exp diff --git a/tests/stress/recursive_gen.py b/tests/stress/recursive_gen.py new file mode 100644 index 0000000000..0e0d3914ee --- /dev/null +++ b/tests/stress/recursive_gen.py @@ -0,0 +1,18 @@ +# test deeply recursive generators + +# simple "yield from" recursion +def gen(): + yield from gen() +try: + list(gen()) +except RuntimeError: + print('RuntimeError') + +# recursion via an iterator over a generator +def gen2(): + for x in gen2(): + yield x +try: + next(gen2()) +except RuntimeError: + print('RuntimeError') diff --git a/tests/misc/recursive_iternext.py b/tests/stress/recursive_iternext.py similarity index 100% rename from tests/misc/recursive_iternext.py rename to tests/stress/recursive_iternext.py diff --git a/tests/misc/recursive_iternext.py.exp b/tests/stress/recursive_iternext.py.exp similarity index 100% rename from tests/misc/recursive_iternext.py.exp rename to tests/stress/recursive_iternext.py.exp diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py index 7a496aa879..13721f1f47 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -38,11 +38,7 @@ except OSError: stream.set_error(0) print(stream.ioctl(0, bytearray(10))) # successful ioctl call -stream2 = data[3] # is textio and sets .write = NULL -try: - print(stream2.write(b'1')) # attempt to call NULL implementation -except OSError: - print('OSError') +stream2 = data[3] # is textio print(stream2.read(1)) # read 1 byte encounters non-blocking error with textio stream # test BufferedWriter with stream errors @@ -71,3 +67,8 @@ try: import frzmpy2 except ZeroDivisionError: print('ZeroDivisionError') + +# test loading a resource from a frozen string +import uio +buf = uio.resource_stream('frzstr_pkg2', 'mod.py') +print(buf.read(21)) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 1db46ab8f4..9df8527577 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -2,6 +2,7 @@ -123 +123 123 -0123 123 +123 1ABCDEF ab abc @@ -12,6 +13,9 @@ false true 80000000 80000000 abc +# GC +0 +0 # vstr tests sts @@ -23,21 +27,29 @@ RuntimeError: # repl ame__ -__name__ path argv version -version_info implementation platform byteorder -maxsize exit stdin stdout -stderr modules exc_info getsizeof -print_exception +__class__ __name__ argv byteorder +exc_info exit getsizeof implementation +maxsize modules path platform +print_exception stderr stdin +stdout version version_info ementation # attrtuple (start=1, stop=2, step=3) # str 1 +# bytearray +data # mpz 1 12345678 0 0 +0 +0 +0 +1 +12345 +6 # runtime utils TypeError: unsupported type for __abs__: 'str' TypeError: unsupported types for __divmod__: 'str', 'str' @@ -47,8 +59,10 @@ Warning: test +1e+00 +1e+00 # binary -122 +123 456 +# VM +2 1 # scheduler sched(0)=1 sched(1)=1 @@ -76,7 +90,6 @@ b'123' b'123' OSError 0 -OSError None None frzstr1 @@ -90,3 +103,4 @@ frzstr_pkg2.mod frzmpy_pkg2.mod 1 ZeroDivisionError +b'# test frozen package' diff --git a/tools/bootstrap_upip.sh b/tools/bootstrap_upip.sh index 667d0845a4..2891775d7d 100755 --- a/tools/bootstrap_upip.sh +++ b/tools/bootstrap_upip.sh @@ -17,7 +17,7 @@ fi # Remove any stale old version rm -rf micropython-upip-* -wget -nd -r -l1 https://pypi.python.org/pypi/micropython-upip/ --accept-regex ".*pypi.python.org/packages/source/.*.gz" --reject=html +wget -nd -rH -l1 -D files.pythonhosted.org https://pypi.org/project/micropython-upip/ --reject=html tar xfz micropython-upip-*.tar.gz tmpd="$PWD" diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index ac7b2c1ccf..eeb760a5f6 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -287,7 +287,9 @@ class RawCode: # generate constant objects for i, obj in enumerate(self.objs): obj_name = 'const_obj_%s_%u' % (self.escaped_name, i) - if is_str_type(obj) or is_bytes_type(obj): + if obj is Ellipsis: + print('#define %s mp_const_ellipsis_obj' % obj_name) + elif is_str_type(obj) or is_bytes_type(obj): if is_str_type(obj): obj = bytes_cons(obj, 'utf8') obj_type = 'mp_type_str' @@ -328,7 +330,6 @@ class RawCode: print('STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};' % (obj_name, obj.real, obj.imag)) else: - # TODO raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,)) # generate constant table, if it has any entries diff --git a/tools/pydfu.py b/tools/pydfu.py index 8c0220de87..a7adda37cc 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -5,7 +5,7 @@ # details. """This module implements enough functionality to program the STM32F4xx over -DFU, without requiringdfu-util. +DFU, without requiring dfu-util. See app note AN3156 for a description of the DFU protocol. See document UM0391 for a dscription of the DFuse file. @@ -81,6 +81,7 @@ def init(): if len(devices) > 1: raise ValueError("Multiple DFU devices found") __dev = devices[0] + __dev.set_configuration() # Claim DFU interface usb.util.claim_interface(__dev, __DFU_INTERFACE) @@ -167,7 +168,7 @@ def write_memory(addr, buf, progress=None, progress_addr=0, progress_size=0): print ("Addr 0x%x %dKBs/%dKBs..." % (xfer_base + xfer_bytes, xfer_bytes // 1024, xfer_total // 1024)) - if progress and xfer_count % 256 == 0: + if progress and xfer_count % 2 == 0: progress(progress_addr, xfer_base + xfer_bytes - progress_addr, progress_size) @@ -175,7 +176,9 @@ def write_memory(addr, buf, progress=None, progress_addr=0, progress_size=0): set_address(xfer_base+xfer_bytes) # Send DNLOAD with fw data - chunk = min(64, xfer_total-xfer_bytes) + # the "2048" is the DFU transfer size supported by the ST DFU bootloader + # TODO: this number should be extracted from the USB config descriptor + chunk = min(2048, xfer_total-xfer_bytes) __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 2, __DFU_INTERFACE, buf[xfer_bytes:xfer_bytes + chunk], __TIMEOUT) @@ -391,24 +394,25 @@ def get_memory_layout(device): intf = cfg[(0, 0)] mem_layout_str = get_string(device, intf.iInterface) mem_layout = mem_layout_str.split('/') - addr = int(mem_layout[1], 0) - segments = mem_layout[2].split(',') - seg_re = re.compile(r'(\d+)\*(\d+)(.)(.)') result = [] - for segment in segments: - seg_match = seg_re.match(segment) - num_pages = int(seg_match.groups()[0], 10) - page_size = int(seg_match.groups()[1], 10) - multiplier = seg_match.groups()[2] - if multiplier == 'K': - page_size *= 1024 - if multiplier == 'M': - page_size *= 1024 * 1024 - size = num_pages * page_size - last_addr = addr + size - 1 - result.append(named((addr, last_addr, size, num_pages, page_size), - "addr last_addr size num_pages page_size")) - addr += size + for mem_layout_index in range(1, len(mem_layout), 2): + addr = int(mem_layout[mem_layout_index], 0) + segments = mem_layout[mem_layout_index + 1].split(',') + seg_re = re.compile(r'(\d+)\*(\d+)(.)(.)') + for segment in segments: + seg_match = seg_re.match(segment) + num_pages = int(seg_match.groups()[0], 10) + page_size = int(seg_match.groups()[1], 10) + multiplier = seg_match.groups()[2] + if multiplier == 'K': + page_size *= 1024 + if multiplier == 'M': + page_size *= 1024 * 1024 + size = num_pages * page_size + last_addr = addr + size - 1 + result.append(named((addr, last_addr, size, num_pages, page_size), + "addr last_addr size num_pages page_size")) + addr += size return result diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index 0f9e628476..7f14db4ba6 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -1,27 +1,30 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 import os, sys from glob import glob from re import sub +import argparse + def escape(s): - lookup = { - '\0': '\\0', - '\t': '\\t', - '\n': '\\n\"\n\"', - '\r': '\\r', - '\\': '\\\\', - '\"': '\\\"', - } - return "\"\"\n\"{}\"".format(''.join([lookup[x] if x in lookup else x for x in s])) + s = s.decode() + lookup = { + '\0': '\\0', + '\t': '\\t', + '\n': '\\n\"\n\"', + '\r': '\\r', + '\\': '\\\\', + '\"': '\\\"', + } + return "\"\"\n\"{}\"".format(''.join([lookup[x] if x in lookup else x for x in s])) def chew_filename(t): - return { 'func': "test_{}_fn".format(sub(r'/|\.|-', '_', t)), 'desc': t.split('/')[1] } + return { 'func': "test_{}_fn".format(sub(r'/|\.|-', '_', t)), 'desc': t } -def script_to_map(t): - r = { 'name': chew_filename(t)['func'] } - with open(t) as test: - script = test.readlines() +def script_to_map(test_file): + r = {"name": chew_filename(test_file)["func"]} + with open(t) as test: + script = test.readlines() # Test for import skip_if and inject it into the test as needed. if "import skip_if\n" in script: @@ -37,12 +40,14 @@ def script_to_map(t): script.insert(index + total_lines, "\t" + line) total_lines += 1 r['script'] = escape(''.join(script)) - return r + return r test_function = ( "void {name}(void* data) {{\n" - " const char * pystr = {script};\n" - " do_str(pystr);\n" + " static const char pystr[] = {script};\n" + " static const char exp[] = {output};\n" + " upytest_set_expected_output(exp, sizeof(exp) - 1);\n" + " upytest_execute_test(pystr);\n" "}}" ) @@ -57,30 +62,62 @@ testgroup_struct = ( "struct testgroup_t groups[] = {{\n{body}\n END_OF_GROUPS\n}};" ) testgroup_member = ( - " {{ \"{name}/\", {name}_tests }}," + " {{ \"{name}\", {name}_tests }}," ) ## XXX: may be we could have `--without ` argument... # currently these tests are selected because they pass on qemu-arm test_dirs = ('basics', 'micropython', 'float', 'extmod', 'inlineasm') # 'import', 'io', 'misc') exclude_tests = ( - 'float/float2int_doubleprec_intbig.py', # requires double precision floating point to work - 'inlineasm/asmfpaddsub.py', 'inlineasm/asmfpcmp.py', 'inlineasm/asmfpldrstr.py', 'inlineasm/asmfpmuldiv.py', 'inlineasm/asmfpsqrt.py', - 'extmod/ticks_diff.py', 'extmod/time_ms_us.py', 'extmod/uheapq_timeq.py', - 'extmod/vfs_fat_ramdisk.py', 'extmod/vfs_fat_fileio.py', 'extmod/vfs_fat_fsusermount.py', 'extmod/vfs_fat_oldproto.py', + # pattern matching in .exp + 'basics/bytes_compare3.py', + 'extmod/ticks_diff.py', + 'extmod/time_ms_us.py', + 'extmod/uheapq_timeq.py', + # unicode char issue + 'extmod/ujson_loads.py', + # doesn't output to python stdout + 'extmod/ure_debug.py', + 'extmod/vfs_basic.py', + 'extmod/vfs_fat_ramdisk.py', 'extmod/vfs_fat_fileio.py', + 'extmod/vfs_fat_fsusermount.py', 'extmod/vfs_fat_oldproto.py', + # rounding issues + 'float/float_divmod.py', + # requires double precision floating point to work + 'float/float2int_doubleprec_intbig.py', + 'float/float_parse_doubleprec.py', + # inline asm FP tests (require Cortex-M4) + 'inlineasm/asmfpaddsub.py', 'inlineasm/asmfpcmp.py', 'inlineasm/asmfpldrstr.py', + 'inlineasm/asmfpmuldiv.py','inlineasm/asmfpsqrt.py', + # different filename in output + 'micropython/emg_exc.py', + 'micropython/heapalloc_traceback.py', + # pattern matching in .exp + 'micropython/meminfo.py', ) output = [] +tests = [] -for group in test_dirs: - tests = [test for test in glob('{}/*.py'.format(group)) if test not in exclude_tests] - output.extend([test_function.format(**script_to_map(test)) for test in tests]) - testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests] - output.append(testcase_struct.format(name=group, body='\n'.join(testcase_members))) +argparser = argparse.ArgumentParser(description='Convert native MicroPython tests to tinytest/upytesthelper C code') +argparser.add_argument('--stdin', action="store_true", help='read list of tests from stdin') +args = argparser.parse_args() -testgroup_members = [testgroup_member.format(name=group) for group in test_dirs] +if not args.stdin: + for group in test_dirs: + tests += [test for test in glob('{}/*.py'.format(group)) if test not in exclude_tests] +else: + for l in sys.stdin: + tests.append(l.rstrip()) + +output.extend([test_function.format(**script_to_map(test)) for test in tests]) +testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests] +output.append(testcase_struct.format(name="", body='\n'.join(testcase_members))) + +testgroup_members = [testgroup_member.format(name=group) for group in [""]] output.append(testgroup_struct.format(body='\n'.join(testgroup_members))) ## XXX: may be we could have `--output ` argument... -print('\n\n'.join(output)) +# Don't depend on what system locale is set, use utf8 encoding. +sys.stdout.buffer.write('\n\n'.join(output).encode('utf8')) diff --git a/tools/upip.py b/tools/upip.py index 411da49e8c..a400c31743 100644 --- a/tools/upip.py +++ b/tools/upip.py @@ -1,3 +1,10 @@ +# +# upip - Package manager for MicroPython +# +# Copyright (c) 2015-2018 Paul Sokolovsky +# +# Licensed under the MIT license. +# import sys import gc import uos as os @@ -110,16 +117,16 @@ def url_open(url): proto, _, host, urlpath = url.split('/', 3) try: - ai = usocket.getaddrinfo(host, 443) + ai = usocket.getaddrinfo(host, 443, 0, usocket.SOCK_STREAM) except OSError as e: fatal("Unable to resolve %s (no Internet?)" % host, e) #print("Address infos:", ai) - addr = ai[0][4] + ai = ai[0] - s = usocket.socket(ai[0][0]) + s = usocket.socket(ai[0], ai[1], ai[2]) try: #print("Connect address:", addr) - s.connect(addr) + s.connect(ai[-1]) if proto == "https:": s = ussl.wrap_socket(s, server_hostname=host) @@ -149,7 +156,7 @@ def url_open(url): def get_pkg_metadata(name): - f = url_open("https://pypi.python.org/pypi/%s/json" % name) + f = url_open("https://pypi.org/pypi/%s/json" % name) try: return json.load(f) finally: