diff --git a/.gitmodules b/.gitmodules index d2d8dd278..c3f4c55ac 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 b98ee9971..d50a5d261 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ compiler: cache: directories: - "${HOME}/persist" +env: + - MAKEOPTS="-j4" before_script: # Extra CPython versions @@ -26,44 +28,47 @@ before_script: - python3 --version script: - - make -C mpy-cross - - make -C ports/minimal CROSS=1 build/firmware.bin + - make ${MAKEOPTS} -C mpy-cross + - make ${MAKEOPTS} -C ports/minimal CROSS=1 build/firmware.bin - ls -l ports/minimal/build/firmware.bin - tools/check_code_size.sh - mkdir -p ${HOME}/persist # Save new firmware for reference, but only if building a main branch, not a pull request - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cp ports/minimal/build/firmware.bin ${HOME}/persist/; fi' - - make -C ports/unix deplibs - - make -C ports/unix - - make -C ports/unix nanbox - - make -C ports/bare-arm - - make -C ports/qemu-arm -f Makefile.test test - - make -C ports/stm32 - - make -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 - - make -C ports/stm32 BOARD=STM32F769DISC - - make -C ports/stm32 BOARD=STM32L476DISC - - make -C ports/teensy - - make -C ports/cc3200 BTARGET=application BTYPE=release - - make -C ports/cc3200 BTARGET=bootloader BTYPE=release - - make -C ports/windows CROSS_COMPILE=i686-w64-mingw32- + - make ${MAKEOPTS} -C ports/unix deplibs + - make ${MAKEOPTS} -C ports/unix + - make ${MAKEOPTS} -C ports/unix nanbox + - make ${MAKEOPTS} -C ports/bare-arm + - make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test test + - make ${MAKEOPTS} -C ports/stm32 + - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1 + - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC + - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC + - make ${MAKEOPTS} -C ports/teensy + - make ${MAKEOPTS} -C ports/cc3200 BTARGET=application BTYPE=release + - make ${MAKEOPTS} -C ports/cc3200 BTARGET=bootloader BTYPE=release + - make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32- # run tests without coverage info #- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests) #- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests --emit native) # run tests with coverage info - - make -C ports/unix coverage + - make ${MAKEOPTS} -C ports/unix coverage - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread) - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native) - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float) + # test when input script comes from stdin + - cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc' + # run coveralls coverage analysis (try to, even if some builds/tests failed) - (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod) # run tests on stackless build - rm -rf ports/unix/build-coverage - - make -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" + - make ${MAKEOPTS} -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1" - (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests) after_failure: diff --git a/docs/esp8266/tutorial/pins.rst b/docs/esp8266/tutorial/pins.rst index cd45c83cd..d304cd55b 100644 --- a/docs/esp8266/tutorial/pins.rst +++ b/docs/esp8266/tutorial/pins.rst @@ -17,7 +17,8 @@ it. To make an input pin use:: >>> pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP) You can either use PULL_UP or None for the input pull-mode. If it's -not specified then it defaults to None, which is no pull resistor. +not specified then it defaults to None, which is no pull resistor. GPIO16 +has no pull-up mode. You can read the value on the pin using:: >>> pin.value() diff --git a/docs/esp8266/tutorial/pwm.rst b/docs/esp8266/tutorial/pwm.rst index 8de509427..61eb190f6 100644 --- a/docs/esp8266/tutorial/pwm.rst +++ b/docs/esp8266/tutorial/pwm.rst @@ -28,8 +28,8 @@ You can set the frequency and duty cycle using:: >>> pwm12.duty(512) Note that the duty cycle is between 0 (all off) and 1023 (all on), with 512 -being a 50% duty. If you print the PWM object then it will tell you its current -configuration:: +being a 50% duty. Values beyond this min/max will be clipped. If you +print the PWM object then it will tell you its current configuration:: >>> pwm12 PWM(12, freq=500, duty=512) diff --git a/docs/library/array.rst b/docs/library/array.rst index d096c6ec4..f837b0343 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/index.rst b/docs/library/index.rst index b141abf1e..af1a0ff69 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -9,34 +9,36 @@ MicroPython libraries * MicroPython implements a subset of Python functionality for each module. * To ease extensibility, MicroPython versions of standard Python modules - usually have ``u`` (micro) prefix. + usually have ``u`` ("micro") prefix. * Any particular MicroPython variant or port may miss any feature/function - described in this general documentation, due to resource constraints. + described in this general documentation (due to resource constraints or + other limitations). This chapter describes modules (function and class libraries) which are built -into MicroPython. There are a few categories of modules: +into MicroPython. There are a few categories of such modules: * Modules which implement a subset of standard Python functionality and are not intended to be extended by the user. * Modules which implement a subset of Python functionality, with a provision for extension by the user (via Python code). * Modules which implement MicroPython extensions to the Python standard libraries. -* Modules specific to a particular port and thus not portable. +* Modules specific to a particular `MicroPython port` and thus not portable. -Note about the availability of modules and their contents: This documentation +Note about the availability of the modules and their contents: This documentation in general aspires to describe all modules and functions/classes which are -implemented in MicroPython. However, MicroPython is highly configurable, and +implemented in MicroPython project. However, MicroPython is highly configurable, and each port to a particular board/embedded system makes available only a subset of MicroPython libraries. For officially supported ports, there is an effort to either filter out non-applicable items, or mark individual descriptions with "Availability:" clauses describing which ports provide a given feature. + With that in mind, please still be warned that some functions/classes -in a module (or even the entire module) described in this documentation may be -unavailable in a particular build of MicroPython on a particular board. The +in a module (or even the entire module) described in this documentation **may be +unavailable** in a particular build of MicroPython on a particular system. The best place to find general information of the availability/non-availability of a particular feature is the "General Information" section which contains -information pertaining to a specific port. +information pertaining to a specific `MicroPython port`. Beyond the built-in libraries described in this documentation, many more modules from the Python standard library, as well as further MicroPython @@ -58,9 +60,9 @@ what done by the `micropython-lib` project mentioned above). On some embedded platforms, where it may be cumbersome to add Python-level wrapper modules to achieve naming compatibility with CPython, micro-modules are available both by their u-name, and also by their non-u-name. The -non-u-name can be overridden by a file of that name in your package path. -For example, ``import json`` will first search for a file ``json.py`` or -directory ``json`` and load that package if it is found. If nothing is found, +non-u-name can be overridden by a file of that name in your library path (``sys.path``). +For example, ``import json`` will first search for a file ``json.py`` (or package +directory ``json``) and load that module if it is found. If nothing is found, it will fallback to loading the built-in ``ujson`` module. .. only:: port_unix diff --git a/docs/library/lcd160cr.rst b/docs/library/lcd160cr.rst index 567994640..bb8e6da22 100644 --- a/docs/library/lcd160cr.rst +++ b/docs/library/lcd160cr.rst @@ -172,7 +172,7 @@ Drawing text ------------ To draw text one sets the position, color and font, and then uses -`write` to draw the text. +`LCD160CR.write` to draw the text. .. method:: LCD160CR.set_pos(x, y) @@ -279,7 +279,7 @@ Touch screen methods .. method:: LCD160CR.is_touched() Returns a boolean: ``True`` if there is currently a touch force on the screen, - `False` otherwise. + ``False`` otherwise. .. method:: LCD160CR.get_touch() diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index d1f923e31..a6ea738ed 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -33,6 +33,18 @@ Functions compilation of scripts, and returns ``None``. Otherwise it returns the current optimisation level. + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + .. function:: alloc_emergency_exception_buf(size) Allocate *size* bytes of RAM for the emergency exception buffer (a good diff --git a/docs/library/network.rst b/docs/library/network.rst index a1190a574..a113209e0 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -383,10 +383,11 @@ parameter should be `id`. * 0 -- visible * 1 -- hidden - .. method:: wlan.status() + .. method:: wlan.status([param]) Return the current status of the wireless connection. + When called with no argument the return value describes the network link status. The possible statuses are defined as constants: * ``STAT_IDLE`` -- no connection and no activity, @@ -396,6 +397,9 @@ parameter should be `id`. * ``STAT_CONNECT_FAIL`` -- failed due to other problems, * ``STAT_GOT_IP`` -- connection successful. + When called with one argument *param* should be a string naming the status + parameter to retrieve. Supported parameters in WiFI STA mode are: ``'rssi'``. + .. method:: wlan.isconnected() In case of STA mode, returns ``True`` if connected to a WiFi access diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 232d04d96..09b97a187 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -24,11 +24,11 @@ Constructors .. class:: pyb.CAN(bus, ...) - Construct a CAN object on the given bus. ``bus`` can be 1-2, or 'YA' or 'YB'. + Construct a CAN object on the given bus. *bus* can be 1-2, or ``'YA'`` or ``'YB'``. With no additional parameters, the CAN object is created but not initialised (it has the settings from the last initialisation of the bus, if any). If extra arguments are given, the bus is initialised. - See ``init`` for parameters of initialisation. + See :meth:`CAN.init` for parameters of initialisation. The physical pins of the CAN busses are: @@ -42,28 +42,31 @@ Class Methods Reset and disable all filter banks and assign how many banks should be available for CAN(1). STM32F405 has 28 filter banks that are shared between the two available CAN bus controllers. - This function configures how many filter banks should be assigned to each. ``nr`` is the number of banks + This function configures how many filter banks should be assigned to each. *nr* is the number of banks that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2). At boot, 14 banks are assigned to each controller. Methods ------- -.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8) +.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8, auto_restart=False) Initialise the CAN bus with the given parameters: - - ``mode`` is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK - - if ``extframe`` is True then the bus uses extended identifiers in the frames + - *mode* is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK + - if *extframe* is True then the bus uses extended identifiers in the frames (29 bits); otherwise it uses standard 11 bit identifiers - - ``prescaler`` is used to set the duration of 1 time quanta; the time quanta + - *prescaler* is used to set the duration of 1 time quanta; the time quanta will be the input clock (PCLK1, see :meth:`pyb.freq()`) divided by the prescaler - - ``sjw`` is the resynchronisation jump width in units of the time quanta; + - *sjw* is the resynchronisation jump width in units of the time quanta; it can be 1, 2, 3, 4 - - ``bs1`` defines the location of the sample point in units of the time quanta; + - *bs1* defines the location of the sample point in units of the time quanta; it can be between 1 and 1024 inclusive - - ``bs2`` defines the location of the transmit point in units of the time quanta; + - *bs2* defines the location of the transmit point in units of the time quanta; it can be between 1 and 16 inclusive + - *auto_restart* sets whether the controller will automatically try and restart + communications after entering the bus-off state; if this is disabled then + :meth:`~CAN.restart()` can be used to leave the bus-off state The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1); @@ -85,17 +88,64 @@ Methods Turn off the CAN bus. +.. method:: CAN.restart() + + Force a software restart of the CAN controller without resetting its + configuration. + + If the controller enters the bus-off state then it will no longer participate + in bus activity. If the controller is not configured to automatically restart + (see :meth:`~CAN.init()`) then this method can be used to trigger a restart, + and the controller will follow the CAN protocol to leave the bus-off state and + go into the error active state. + +.. method:: CAN.state() + + Return the state of the controller. The return value can be one of: + + - ``CAN.STOPPED`` -- the controller is completely off and reset; + - ``CAN.ERROR_ACTIVE`` -- the controller is on and in the Error Active state + (both TEC and REC are less than 96); + - ``CAN.ERROR_WARNING`` -- the controller is on and in the Error Warning state + (at least one of TEC or REC is 96 or greater); + - ``CAN.ERROR_PASSIVE`` -- the controller is on and in the Error Passive state + (at least one of TEC or REC is 128 or greater); + - ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity + (TEC overflowed beyond 255). + +.. method:: CAN.info([list]) + + Get information about the controller's error states and TX and RX buffers. + If *list* is provided then it should be a list object with at least 8 entries, + which will be filled in with the information. Otherwise a new list will be + created and filled in. In both cases the return value of the method is the + populated list. + + The values in the list are: + + - TEC value + - REC value + - number of times the controller enterted the Error Warning state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Error Passive state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Bus Off state (wrapped + around to 0 after 65535) + - number of pending TX messages + - number of pending RX messages on fifo 0 + - number of pending RX messages on fifo 1 + .. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: - - ``bank`` is the filter bank that is to be configured. - - ``mode`` is the mode the filter should operate in. - - ``fifo`` is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter. - - ``params`` is an array of values the defines the filter. The contents of the array depends on the ``mode`` argument. + - *bank* is the filter bank that is to be configured. + - *mode* is the mode the filter should operate in. + - *fifo* is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter. + - *params* is an array of values the defines the filter. The contents of the array depends on the *mode* argument. +-----------+---------------------------------------------------------+ - |``mode`` |contents of parameter array | + |*mode* |contents of *params* array | +===========+=========================================================+ |CAN.LIST16 |Four 16 bit ids that will be accepted | +-----------+---------------------------------------------------------+ @@ -110,13 +160,13 @@ Methods |CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.| +-----------+---------------------------------------------------------+ - - ``rtr`` is an array of booleans that states if a filter should accept a + - *rtr* is an array of booleans that states if a filter should accept a remote transmission request message. If this argument is not given - then it defaults to False for all entries. The length of the array - depends on the ``mode`` argument. + then it defaults to ``False`` for all entries. The length of the array + depends on the *mode* argument. +-----------+----------------------+ - |``mode`` |length of rtr array | + |*mode* |length of *rtr* array | +===========+======================+ |CAN.LIST16 |4 | +-----------+----------------------+ @@ -131,18 +181,19 @@ Methods Clear and disables a filter bank: - - ``bank`` is the filter bank that is to be cleared. + - *bank* is the filter bank that is to be cleared. .. method:: CAN.any(fifo) Return ``True`` if any message waiting on the FIFO, else ``False``. -.. method:: CAN.recv(fifo, \*, timeout=5000) +.. method:: CAN.recv(fifo, list=None, \*, timeout=5000) Receive data on the bus: - - ``fifo`` is an integer, which is the FIFO to receive on - - ``timeout`` is the timeout in milliseconds to wait for the receive. + - *fifo* is an integer, which is the FIFO to receive on + - *list* is an optional list object to be used as the return value + - *timeout* is the timeout in milliseconds to wait for the receive. Return value: A tuple containing four values. @@ -151,17 +202,35 @@ Methods - The FMI (Filter Match Index) value. - An array containing the data. + If *list* is ``None`` then a new tuple will be allocated, as well as a new + bytes object to contain the data (as the fourth element in the tuple). + + If *list* is not ``None`` then it should be a list object with a least four + elements. The fourth element should be a memoryview object which is created + from either a bytearray or an array of type 'B' or 'b', and this array must + have enough room for at least 8 bytes. The list object will then be + populated with the first three return values above, and the memoryview object + will be resized inplace to the size of the data and filled in with that data. + The same list and memoryview objects can be reused in subsequent calls to + this method, providing a way of receiving data without using the heap. + For example:: + + buf = bytearray(8) + lst = [0, 0, 0, memoryview(buf)] + # No heap memory is allocated in the following call + can.recv(0, lst) + .. method:: CAN.send(data, id, \*, timeout=0, rtr=False) Send a message on the bus: - - ``data`` is the data to send (an integer to send, or a buffer object). - - ``id`` is the id of the message to be sent. - - ``timeout`` is the timeout in milliseconds to wait for the send. - - ``rtr`` is a boolean that specifies if the message shall be sent as - a remote transmission request. If ``rtr`` is True then only the length - of ``data`` is used to fill in the DLC slot of the frame; the actual - bytes in ``data`` are unused. + - *data* is the data to send (an integer to send, or a buffer object). + - *id* is the id of the message to be sent. + - *timeout* is the timeout in milliseconds to wait for the send. + - *rtr* is a boolean that specifies if the message shall be sent as + a remote transmission request. If *rtr* is True then only the length + of *data* is used to fill in the DLC slot of the frame; the actual + bytes in *data* are unused. If timeout is 0 the message is placed in a buffer in one of three hardware buffers and the method returns immediately. If all three buffers are in use @@ -175,8 +244,8 @@ Methods Register a function to be called when a message is accepted into a empty fifo: - - ``fifo`` is the receiving fifo. - - ``fun`` is the function to be called when the fifo becomes non empty. + - *fifo* is the receiving fifo. + - *fun* is the function to be called when the fifo becomes non empty. The callback function takes two arguments the first is the can object it self the second is a integer that indicates the reason for the callback. @@ -209,15 +278,23 @@ Constants --------- .. data:: CAN.NORMAL -.. data:: CAN.LOOPBACK -.. data:: CAN.SILENT -.. data:: CAN.SILENT_LOOPBACK + CAN.LOOPBACK + CAN.SILENT + CAN.SILENT_LOOPBACK - the mode of the CAN bus + The mode of the CAN bus used in :meth:`~CAN.init()`. + +.. data:: CAN.STOPPED + CAN.ERROR_ACTIVE + CAN.ERROR_WARNING + CAN.ERROR_PASSIVE + CAN.BUS_OFF + + Possible states of the CAN controller returned from :meth:`~CAN.state()`. .. data:: CAN.LIST16 -.. data:: CAN.MASK16 -.. data:: CAN.LIST32 -.. data:: CAN.MASK32 + CAN.MASK16 + CAN.LIST32 + CAN.MASK32 - the operation mode of a filter + The operation mode of a filter used in :meth:`~CAN.setfilter()`. diff --git a/docs/library/pyb.Switch.rst b/docs/library/pyb.Switch.rst index e5ab6bd84..1edcbf848 100644 --- a/docs/library/pyb.Switch.rst +++ b/docs/library/pyb.Switch.rst @@ -38,7 +38,7 @@ Methods .. method:: Switch.value() - Get the switch state. Returns `True` if pressed down, otherwise `False`. + Get the switch state. Returns ``True`` if pressed down, otherwise ``False``. .. method:: Switch.callback(fun) diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 799160145..141c270b3 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -278,7 +278,8 @@ Miscellaneous functions - ``None``: disables USB - ``'VCP'``: enable with VCP (Virtual COM Port) interface - - ``'VCP+MSC'``: enable with VCP and MSC (mass storage device class) + - ``'MSC'``: enable with MSC (mass storage device class) interface + - ``'VCP+MSC'``: enable with VCP and MSC - ``'VCP+HID'``: enable with VCP and HID (human interface device) For backwards compatibility, ``'CDC'`` is understood to mean diff --git a/docs/library/uio.rst b/docs/library/uio.rst index 7e6c93228..81420702d 100644 --- a/docs/library/uio.rst +++ b/docs/library/uio.rst @@ -81,7 +81,7 @@ Functions Open a file. Builtin ``open()`` function is aliased to this function. All ports (which provide access to file system) are required to support - `mode` parameter, but support for other arguments vary by port. + *mode* parameter, but support for other arguments vary by port. Classes ------- @@ -103,7 +103,7 @@ Classes text-mode I/O (similar to a normal file opened with "t" modifier). `BytesIO` is used for binary-mode I/O (similar to a normal file opened with "b" modifier). Initial contents of file-like objects - can be specified with `string` parameter (should be normal string + can be specified with *string* parameter (should be normal string for `StringIO` or bytes object for `BytesIO`). All the usual file methods like ``read()``, ``write()``, ``seek()``, ``flush()``, ``close()`` are available on these objects, and additionally, a diff --git a/docs/library/ujson.rst b/docs/library/ujson.rst index 0932d0ab5..5668eb21a 100644 --- a/docs/library/ujson.rst +++ b/docs/library/ujson.rst @@ -12,11 +12,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/uos.rst b/docs/library/uos.rst index c7fa4b308..27f339bb1 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -6,11 +6,32 @@ |see_cpython_module| :mod:`python:os`. -The ``uos`` module contains functions for filesystem access and ``urandom`` -function. +The ``uos`` module contains functions for filesystem access and mounting, +terminal redirection and duplication, and the ``uname`` and ``urandom`` +functions. -Functions ---------- +General functions +----------------- + +.. function:: uname() + + Return a tuple (possibly a named tuple) containing information about the + underlying machine and/or its operating system. The tuple has five fields + in the following order, each of them being a string: + + * ``sysname`` -- the name of the underlying system + * ``nodename`` -- the network name (can be the same as ``sysname``) + * ``release`` -- the version of the underlying system + * ``version`` -- the MicroPython version and build date + * ``machine`` -- an identifier for the underlying hardware (eg board, CPU) + +.. function:: urandom(n) + + Return a bytes object with *n* random bytes. Whenever possible, it is + generated by the hardware random number generator. + +Filesystem access +----------------- .. function:: chdir(path) @@ -22,11 +43,11 @@ Functions .. function:: ilistdir([dir]) - This function returns an iterator which then yields 3-tuples corresponding to + This function returns an iterator which then yields tuples corresponding to the entries in the directory that it is listing. With no argument it lists the current directory, otherwise it lists the directory given by *dir*. - The 3-tuples have the form *(name, type, inode)*: + The tuples have the form *(name, type, inode[, size])*: - *name* is a string (or bytes if *dir* is a bytes object) and is the name of the entry; @@ -34,6 +55,10 @@ Functions directories and 0x8000 for regular files; - *inode* is an integer corresponding to the inode of the file, and may be 0 for filesystems that don't have such a notion. + - Some platforms may return a 4-tuple that includes the entry's *size*. For + file entries, *size* is an integer representing the size of the file + or -1 if unknown. Its meaning is currently undefined for directory + entries. .. function:: listdir([dir]) @@ -84,10 +109,8 @@ Functions Sync all filesystems. -.. function:: urandom(n) - - Return a bytes object with n random bytes. Whenever possible, it is - generated by the hardware random number generator. +Terminal redirection and duplication +------------------------------------ .. function:: dupterm(stream_object, index=0) @@ -108,3 +131,119 @@ Functions the slot given by *index*. The function returns the previous stream-like object in the given slot. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +.. function:: mount(fsobj, mount_point, \*, readonly) + + Mount the filesystem object *fsobj* at the location in the VFS given by the + *mount_point* string. *fsobj* can be a a VFS object that has a ``mount()`` + method, or a block device. If it's a block device then the filesystem type + is automatically detected (an exception is raised if no filesystem was + recognised). *mount_point* may be ``'/'`` to mount *fsobj* at the root, + or ``'/'`` to mount it at a subdirectory under the root. + + If *readonly* is ``True`` then the filesystem is mounted read-only. + + During the mount process the method ``mount()`` is called on the filesystem + object. + + Will raise ``OSError(EPERM)`` if *mount_point* is already mounted. + +.. function:: umount(mount_point) + + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + +.. class:: VfsFat(block_dev) + + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + + .. staticmethod:: mkfs(block_dev) + + Build a FAT filesystem on *block_dev*. + +Block devices +------------- + +A block device is an object which implements the block protocol, which is a set +of methods described below by the :class:`AbstractBlockDev` class. A concrete +implementation of this class will usually allow access to the memory-like +functionality a piece of hardware (like flash memory). A block device can be +used by a particular filesystem driver to store the data for its filesystem. + +.. class:: AbstractBlockDev(...) + + Construct a block device object. The parameters to the constructor are + dependent on the specific block device. + + .. method:: readblocks(block_num, buf) + + Starting at *block_num*, read blocks from the device into *buf* (an array + of bytes). The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + + .. method:: writeblocks(block_num, buf) + + Starting at *block_num*, write blocks from *buf* (an array of bytes) to + the device. The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + .. method:: ioctl(op, arg) + + Control the block device and query its parameters. The operation to + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 5 -- get the number of bytes in a block, should return an integer, + or ``None`` in which case the default value of 512 is used + (*arg* is unused) + +By way of example, the following class will implement a block device that stores +its data in RAM using a ``bytearray``:: + + class RAMBlockDev: + def __init__(self, block_size, num_blocks): + self.block_size = block_size + self.data = bytearray(block_size * num_blocks) + + def readblocks(self, block_num, buf): + for i in range(len(buf)): + buf[i] = self.data[block_num * self.block_size + i] + + def writeblocks(self, block_num, buf): + for i in range(len(buf)): + self.data[block_num * self.block_size + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return len(self.data) // self.block_size + if op == 5: # get block size + return self.block_size + +It can be used as follows:: + + import uos + + bdev = RAMBlockDev(512, 50) + uos.VfsFat.mkfs(bdev) + vfs = uos.VfsFat(bdev) + uos.mount(vfs, '/ramdisk') diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index fb43f7e63..77d458473 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -35,10 +35,10 @@ Methods Register `stream` *obj* for polling. *eventmask* is logical OR of: - * `uselect.POLLIN` - data available for reading - * `uselect.POLLOUT` - more data can be written + * ``uselect.POLLIN`` - data available for reading + * ``uselect.POLLOUT`` - more data can be written - Note that flags like `uselect.POLLHUP` and `uselect.POLLERR` are + Note that flags like ``uselect.POLLHUP`` and ``uselect.POLLERR`` are *not* valid as input eventmask (these are unsolicited events which will be returned from `poll()` regardless of whether they are asked for). This semantics is per POSIX. @@ -63,7 +63,7 @@ Methods tuple, depending on a platform and version, so don't assume that its size is 2. The ``event`` element specifies which events happened with a stream and is a combination of ``uselect.POLL*`` constants described above. Note that - flags `uselect.POLLHUP` and `uselect.POLLERR` can be returned at any time + flags ``uselect.POLLHUP`` and ``uselect.POLLERR`` can be returned at any time (even if were not asked for), and must be acted on accordingly (the corresponding stream unregistered from poll and likely closed), because otherwise all further invocations of `poll()` may return immediately with diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst index de55fc14c..3ae477a9a 100644 --- a/docs/library/usocket.rst +++ b/docs/library/usocket.rst @@ -99,7 +99,7 @@ Functions of error in this function. MicroPython doesn't have ``socket.gaierror`` and raises OSError directly. Note that error numbers of `getaddrinfo()` form a separate namespace and may not match error numbers from - `uerrno` module. To distinguish `getaddrinfo()` errors, they are + the :mod:`uerrno` module. To distinguish `getaddrinfo()` errors, they are represented by negative numbers, whereas standard system errors are positive numbers (error numbers are accessible using ``e.args[0]`` property from an exception object). The use of negative values is a provisional diff --git a/docs/library/ussl.rst b/docs/library/ussl.rst index 903a351f4..be84dc054 100644 --- a/docs/library/ussl.rst +++ b/docs/library/ussl.rst @@ -18,10 +18,10 @@ Functions Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), and returns an instance of ssl.SSLSocket, which wraps the underlying stream in an SSL context. Returned object has the usual `stream` interface methods like - `read()`, `write()`, etc. In MicroPython, the returned object does not expose - socket interface and methods like `recv()`, `send()`. In particular, a + ``read()``, ``write()``, etc. In MicroPython, the returned object does not expose + socket interface and methods like ``recv()``, ``send()``. In particular, a server-side SSL socket should be created from a normal socket returned from - `accept()` on a non-SSL listening server socket. + :meth:`~usocket.socket.accept()` on a non-SSL listening server socket. Depending on the underlying module implementation in a particular `MicroPython port`, some or all keyword arguments above may be not supported. diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index e7de459bc..edac0ae68 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -185,7 +185,7 @@ a file it will save RAM if this is done in a piecemeal fashion. Rather than creating a large string object, create a substring and feed it to the stream before dealing with the next. -The best way to create dynamic strings is by means of the string `format` +The best way to create dynamic strings is by means of the string ``format()`` method: .. code:: @@ -259,7 +259,7 @@ were a string. **Runtime compiler execution** The Python funcitons `eval` and `exec` invoke the compiler at runtime, which -requires significant amounts of RAM. Note that the `pickle` library from +requires significant amounts of RAM. Note that the ``pickle`` library from `micropython-lib` employs `exec`. It may be more RAM efficient to use the `ujson` library for object serialisation. diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index e1609985a..8be2461c2 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -42,7 +42,7 @@ size, which means that to uncompress a compressed stream, 32KB of contguous memory needs to be allocated. This requirement may be not satisfiable on low-memory devices, which may have total memory available less than that amount, and even if not, a contiguous block like that -may be hard to allocate due to `memory fragmentation`. To accommodate +may be hard to allocate due to memory fragmentation. To accommodate these constraints, MicroPython distribution packages use Gzip compression with the dictionary size of 4K, which should be a suitable compromise with still achieving some compression while being able to uncompressed @@ -243,7 +243,7 @@ the data files as "resources", and abstracting away access to them. Python supports resource access using its "setuptools" library, using ``pkg_resources`` module. MicroPython, following its usual approach, implements subset of the functionality of that module, specifically -`pkg_resources.resource_stream(package, resource)` function. +``pkg_resources.resource_stream(package, resource)`` function. The idea is that an application calls this function, passing a resource identifier, which is a relative path to data file within the specified package (usually top-level application package). It diff --git a/docs/reference/repl.rst b/docs/reference/repl.rst index 7a683ca22..1eccb9a88 100644 --- a/docs/reference/repl.rst +++ b/docs/reference/repl.rst @@ -19,7 +19,7 @@ If your cursor is all the way back at the beginning, pressing RETURN will then execute the code that you've entered. The following shows what you'd see after entering a for statement (the underscore shows where the cursor winds up): - >>> for i in range(3): + >>> for i in range(30): ... _ If you then enter an if statement, an additional level of indentation will be @@ -58,9 +58,10 @@ Auto-completion While typing a command at the REPL, if the line typed so far corresponds to the beginning of the name of something, then pressing TAB will show -possible things that could be entered. For example type ``m`` and press TAB -and it should expand to ``machine``. Enter a dot ``.`` and press TAB again. You -should see something like: +possible things that could be entered. For example, first import the machine +module by entering ``import machine`` and pressing RETURN. +Then type ``m`` and press TAB and it should expand to ``machine``. +Enter a dot ``.`` and press TAB again. You should see something like: >>> machine. __name__ info unique_id reset @@ -151,7 +152,7 @@ method by which you're connected to the MicroPython board (USB-serial, or Wifi). You can perform a soft reset from the REPL by pressing Ctrl-D, or from your python code by executing: :: - raise SystemExit + machine.soft_reset() For example, if you reset your MicroPython board, and you execute a dir() command, you'd see something like this: diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index 279a1bbcd..4db60ec14 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -63,8 +63,8 @@ used for communication with a device. A typical driver will create the buffer in constructor and use it in its I/O methods which will be called repeatedly. The MicroPython libraries typically provide support for pre-allocated buffers. For -example, objects which support stream interface (e.g., file or UART) provide `read()` -method which allocates new buffer for read data, but also a `readinto()` method +example, objects which support stream interface (e.g., file or UART) provide ``read()`` +method which allocates new buffer for read data, but also a ``readinto()`` method to read data into an existing buffer. Floating Point @@ -109,10 +109,10 @@ the 10K buffer go (be ready for garbage collection), instead of making a long-living memoryview and keeping 10K blocked for GC. Nonetheless, `memoryview` is indispensable for advanced preallocated buffer -management. `readinto()` method discussed above puts data at the beginning +management. ``readinto()`` method discussed above puts data at the beginning of buffer and fills in entire buffer. What if you need to put data in the middle of existing buffer? Just create a memoryview into the needed section -of buffer and pass it to `readinto()`. +of buffer and pass it to ``readinto()``. Identifying the slowest section of code --------------------------------------- @@ -326,7 +326,7 @@ standard approach would be to write mypin.value(mypin.value() ^ 1) # mypin was instantiated as an output pin -This involves the overhead of two calls to the `Pin` instance's :meth:`~machine.Pin.value()` +This involves the overhead of two calls to the :class:`~machine.Pin` instance's :meth:`~machine.Pin.value()` method. This overhead can be eliminated by performing a read/write to the relevant bit of the chip's GPIO port output data register (odr). To facilitate this the ``stm`` module provides a set of constants providing the addresses of the relevant registers. diff --git a/drivers/bus/qspi.h b/drivers/bus/qspi.h new file mode 100644 index 000000000..31c9d14fc --- /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 000000000..10c599246 --- /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 000000000..bc12d89d3 --- /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 000000000..6d1b9c2f8 --- /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/cc3000/src/ccspi.c b/drivers/cc3000/src/ccspi.c index 820be809b..1dcd61884 100644 --- a/drivers/cc3000/src/ccspi.c +++ b/drivers/cc3000/src/ccspi.c @@ -50,7 +50,7 @@ #endif // these need to be set to valid values before anything in this file will work -STATIC SPI_HandleTypeDef *SPI_HANDLE = NULL; +STATIC const spi_t *SPI_HANDLE = NULL; STATIC const pin_obj_t *PIN_CS = NULL; STATIC const pin_obj_t *PIN_EN = NULL; STATIC const pin_obj_t *PIN_IRQ = NULL; @@ -134,17 +134,18 @@ void SpiOpen(gcSpiHandleRx pfRxHandler) wlan_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; /* SPI configuration */ - SPI_HANDLE->Init.Mode = SPI_MODE_MASTER; - SPI_HANDLE->Init.Direction = SPI_DIRECTION_2LINES; - SPI_HANDLE->Init.DataSize = SPI_DATASIZE_8BIT; - SPI_HANDLE->Init.CLKPolarity = SPI_POLARITY_LOW; - SPI_HANDLE->Init.CLKPhase = SPI_PHASE_2EDGE; - SPI_HANDLE->Init.NSS = SPI_NSS_SOFT; - SPI_HANDLE->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; - SPI_HANDLE->Init.FirstBit = SPI_FIRSTBIT_MSB; - SPI_HANDLE->Init.TIMode = SPI_TIMODE_DISABLED; - SPI_HANDLE->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; - SPI_HANDLE->Init.CRCPolynomial = 7; + SPI_InitTypeDef *init = &SPI_HANDLE->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; + init->CLKPhase = SPI_PHASE_2EDGE; + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; spi_init(SPI_HANDLE, false); // configure wlan CS and EN pins @@ -167,7 +168,7 @@ void SpiOpen(gcSpiHandleRx pfRxHandler) actual communications start, it might be required */ CS_LOW(); uint8_t buf[1]; - HAL_SPI_Receive(SPI_HANDLE, buf, sizeof(buf), SPI_TIMEOUT); + HAL_SPI_Receive(SPI_HANDLE->spi, buf, sizeof(buf), SPI_TIMEOUT); CS_HIGH(); // register EXTI @@ -192,7 +193,7 @@ STATIC void SpiWriteDataSynchronous(unsigned char *data, unsigned short size) { DEBUG_printf("SpiWriteDataSynchronous(data=%p [%x %x %x %x], size=%u)\n", data, data[0], data[1], data[2], data[3], size); __disable_irq(); - if (HAL_SPI_TransmitReceive(SPI_HANDLE, data, data, size, SPI_TIMEOUT) != HAL_OK) { + if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) { //BREAK(); } __enable_irq(); @@ -203,7 +204,7 @@ STATIC void SpiReadDataSynchronous(unsigned char *data, unsigned short size) { memset(data, READ, size); __disable_irq(); - if (HAL_SPI_TransmitReceive(SPI_HANDLE, data, data, size, SPI_TIMEOUT) != HAL_OK) { + if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) { //BREAK(); } __enable_irq(); diff --git a/drivers/dht/dht.py b/drivers/dht/dht.py new file mode 100644 index 000000000..eed61df7c --- /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/drivers/display/ssd1306.py b/drivers/display/ssd1306.py index cebe10e67..178b4911d 100644 --- a/drivers/display/ssd1306.py +++ b/drivers/display/ssd1306.py @@ -32,7 +32,7 @@ class SSD1306(framebuf.FrameBuffer): self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) - super.__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) self.init_display() def init_display(self): diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index 08564d054..d72603f64 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016-2017 Damien P. George + * Copyright (c) 2016-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,57 +29,117 @@ #include "py/mperrno.h" #include "py/mphal.h" -#include "extmod/machine_spi.h" #include "drivers/memory/spiflash.h" -#define CMD_WRITE (0x02) -#define CMD_READ (0x03) -#define CMD_WRDI (0x04) -#define CMD_RDSR (0x05) -#define CMD_WREN (0x06) -#define CMD_SEC_ERASE (0x20) +#define QSPI_QE_MASK (0x02) +#define USE_WR_DELAY (1) + +#define CMD_WRSR (0x01) +#define CMD_WRITE (0x02) +#define CMD_READ (0x03) +#define CMD_RDSR (0x05) +#define CMD_WREN (0x06) +#define CMD_SEC_ERASE (0x20) +#define CMD_RDCR (0x35) +#define CMD_RD_DEVID (0x9f) +#define CMD_CHIP_ERASE (0xc7) +#define CMD_C4READ (0xeb) + #define WAIT_SR_TIMEOUT (1000000) #define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer #define SECTOR_SIZE (4096) // size of erase sector // Note: this code is not reentrant with this shared buffer -STATIC uint8_t buf[SECTOR_SIZE]; - -void mp_spiflash_init(mp_spiflash_t *self) { - mp_hal_pin_write(self->cs, 1); - mp_hal_pin_output(self->cs); - const mp_machine_spi_p_t *protocol = self->spi->type->protocol; - protocol->init(self->spi, 0, NULL, (mp_map_t*)&mp_const_empty_map); -} +STATIC uint8_t buf[SECTOR_SIZE] __attribute__((aligned(4))); +STATIC mp_spiflash_t *bufuser; // current user of buf +STATIC uint32_t bufsec; // current sector stored in buf; 0xffffffff if invalid STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) { - // can be used for actions needed to acquire bus - (void)self; + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) { + c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_ACQUIRE); + } } STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) { - // can be used for actions needed to release bus - (void)self; + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) { + c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_RELEASE); + } } -STATIC void mp_spiflash_transfer(mp_spiflash_t *self, size_t len, const uint8_t *src, uint8_t *dest) { - const mp_machine_spi_p_t *protocol = self->spi->type->protocol; - protocol->transfer(self->spi, len, src, dest); +STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t data) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + // Note: len/data are unused for standard SPI + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->write_cmd_data(c->bus.u_qspi.data, cmd, len, data); + } +} + +STATIC void mp_spiflash_write_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint8_t buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); + if (len) { + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, src, NULL); + } + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src); + } +} + +STATIC uint32_t mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint32_t buf; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, (void*)&buf, (void*)&buf); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + return buf; + } else { + return c->bus.u_qspi.proto->read_cmd(c->bus.u_qspi.data, cmd, len); + } +} + +STATIC void mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint8_t buf[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, dest, dest); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, CMD_C4READ, addr, len, dest); + } +} + +STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) { + mp_spiflash_write_cmd_data(self, cmd, 0, 0); +} + +STATIC void mp_spiflash_write_cmd_addr(mp_spiflash_t *self, uint8_t cmd, uint32_t addr) { + mp_spiflash_write_cmd_addr_data(self, cmd, addr, 0, NULL); } STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) { - uint8_t cmd[1] = {CMD_RDSR}; - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 1, cmd, NULL); + uint8_t sr; for (; timeout; --timeout) { - mp_spiflash_transfer(self, 1, cmd, cmd); - if ((cmd[0] & mask) == val) { + sr = mp_spiflash_read_cmd(self, CMD_RDSR, 1); + if ((sr & mask) == val) { break; } } - mp_hal_pin_write(self->cs, 1); - if ((cmd[0] & mask) == val) { + if ((sr & mask) == val) { return 0; // success } else if (timeout == 0) { return -MP_ETIMEDOUT; @@ -96,10 +156,40 @@ STATIC int mp_spiflash_wait_wip0(mp_spiflash_t *self) { return mp_spiflash_wait_sr(self, 1, 0, WAIT_SR_TIMEOUT); } -STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) { - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 1, &cmd, NULL); - mp_hal_pin_write(self->cs, 1); +void mp_spiflash_init(mp_spiflash_t *self) { + self->flags = 0; + + if (self->config->bus_kind == MP_SPIFLASH_BUS_SPI) { + mp_hal_pin_write(self->config->bus.u_spi.cs, 1); + mp_hal_pin_output(self->config->bus.u_spi.cs); + self->config->bus.u_spi.proto->ioctl(self->config->bus.u_spi.data, MP_SPI_IOCTL_INIT); + } else { + self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT); + } + + mp_spiflash_acquire_bus(self); + + #if defined(CHECK_DEVID) + // Validate device id + uint32_t devid = mp_spiflash_read_cmd(self, CMD_RD_DEVID, 3); + if (devid != CHECK_DEVID) { + return 0; + } + #endif + + if (self->config->bus_kind == MP_SPIFLASH_BUS_QSPI) { + // Set QE bit + uint32_t data = (mp_spiflash_read_cmd(self, CMD_RDSR, 1) & 0xff) + | (mp_spiflash_read_cmd(self, CMD_RDCR, 1) & 0xff) << 8; + if (!(data & (QSPI_QE_MASK << 8))) { + data |= QSPI_QE_MASK << 8; + mp_spiflash_write_cmd(self, CMD_WREN); + mp_spiflash_write_cmd_data(self, CMD_WRSR, 2, data); + mp_spiflash_wait_wip0(self); + } + } + + mp_spiflash_release_bus(self); } STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { @@ -113,10 +203,7 @@ STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { } // erase the sector - mp_hal_pin_write(self->cs, 0); - uint8_t cmd[4] = {CMD_SEC_ERASE, addr >> 16, addr >> 8, addr}; - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_hal_pin_write(self->cs, 1); + mp_spiflash_write_cmd_addr(self, CMD_SEC_ERASE, addr); // wait WIP=0 return mp_spiflash_wait_wip0(self); @@ -133,67 +220,224 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint } // write the page - mp_hal_pin_write(self->cs, 0); - uint8_t cmd[4] = {CMD_WRITE, addr >> 16, addr >> 8, addr}; - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_spiflash_transfer(self, PAGE_SIZE, src, NULL); - mp_hal_pin_write(self->cs, 1); + mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, PAGE_SIZE, src); // wait WIP=0 return mp_spiflash_wait_wip0(self); } void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + if (len == 0) { + return; + } mp_spiflash_acquire_bus(self); - uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_spiflash_transfer(self, len, dest, dest); - mp_hal_pin_write(self->cs, 1); + if (bufuser == self && bufsec != 0xffffffff) { + uint32_t bis = addr / SECTOR_SIZE; + uint32_t bie = (addr + len - 1) / SECTOR_SIZE; + if (bis <= bufsec && bufsec <= bie) { + // Read straddles current buffer + size_t rest = 0; + if (bis < bufsec) { + // Read direct from flash for first part + rest = bufsec * SECTOR_SIZE - addr; + mp_spiflash_read_data(self, addr, rest, dest); + len -= rest; + dest += rest; + addr += rest; + } + uint32_t offset = addr & (SECTOR_SIZE - 1); + rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; + } + memcpy(dest, &buf[offset], rest); + len -= rest; + if (len == 0) { + mp_spiflash_release_bus(self); + return; + } + dest += rest; + addr += rest; + } + } + // Read rest direct from flash + mp_spiflash_read_data(self, addr, len, dest); mp_spiflash_release_bus(self); } -int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { - // TODO optimise so we don't need to erase multiple times for successive writes to a sector +STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) { + #if USE_WR_DELAY + if (!(self->flags & 1)) { + return; + } - // align to 4096 sector + self->flags &= ~1; + + // Erase sector + int ret = mp_spiflash_erase_sector(self, bufsec * SECTOR_SIZE); + if (ret != 0) { + return; + } + + // Write + for (int i = 0; i < 16; i += 1) { + int ret = mp_spiflash_write_page(self, bufsec * SECTOR_SIZE + i * PAGE_SIZE, buf + i * PAGE_SIZE); + if (ret != 0) { + return; + } + } + #endif +} + +void mp_spiflash_flush(mp_spiflash_t *self) { + mp_spiflash_acquire_bus(self); + mp_spiflash_flush_internal(self); + mp_spiflash_release_bus(self); +} + +STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + // Align to 4096 sector uint32_t offset = addr & 0xfff; - addr = (addr >> 12) << 12; + uint32_t sec = addr >> 12; + addr = sec << 12; - // restriction for now, so we don't need to erase multiple pages + // Restriction for now, so we don't need to erase multiple pages if (offset + len > sizeof(buf)) { - printf("mp_spiflash_write: len is too large\n"); + printf("mp_spiflash_write_part: len is too large\n"); return -MP_EIO; } - mp_spiflash_acquire_bus(self); - - // read sector - uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_spiflash_transfer(self, SECTOR_SIZE, buf, buf); - mp_hal_pin_write(self->cs, 1); - - // erase sector - int ret = mp_spiflash_erase_sector(self, addr); - if (ret != 0) { - mp_spiflash_release_bus(self); - return ret; + // Acquire the sector buffer + if (bufuser != self) { + if (bufuser != NULL) { + mp_spiflash_flush(bufuser); + } + bufuser = self; + bufsec = 0xffffffff; } - // copy new block into buffer + if (bufsec != sec) { + // Read sector + #if USE_WR_DELAY + if (bufsec != 0xffffffff) { + mp_spiflash_flush_internal(self); + } + #endif + mp_spiflash_read_data(self, addr, SECTOR_SIZE, buf); + } + + #if USE_WR_DELAY + + bufsec = sec; + // Just copy to buffer + memcpy(buf + offset, src, len); + // And mark dirty + self->flags |= 1; + + #else + + uint32_t dirty = 0; + for (size_t i = 0; i < len; ++i) { + if (buf[offset + i] != src[i]) { + if (buf[offset + i] != 0xff) { + // Erase sector + int ret = mp_spiflash_erase_sector(self, addr); + if (ret != 0) { + return ret; + } + dirty = 0xffff; + break; + } else { + dirty |= (1 << ((offset + i) >> 8)); + } + } + } + + bufsec = sec; + // Copy new block into buffer memcpy(buf + offset, src, len); - // write sector in pages of 256 bytes - for (int i = 0; i < SECTOR_SIZE; i += 256) { - ret = mp_spiflash_write_page(self, addr + i, buf + i); + // Write sector in pages of 256 bytes + for (size_t i = 0; i < 16; ++i) { + if (dirty & (1 << i)) { + int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, buf + i * PAGE_SIZE); + if (ret != 0) { + return ret; + } + } + } + + #endif + + return 0; // success +} + +int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + uint32_t bis = addr / SECTOR_SIZE; + uint32_t bie = (addr + len - 1) / SECTOR_SIZE; + + mp_spiflash_acquire_bus(self); + + if (bufuser == self && bis <= bufsec && bie >= bufsec) { + // Write straddles current buffer + uint32_t pre; + uint32_t offset; + if (bufsec * SECTOR_SIZE >= addr) { + pre = bufsec * SECTOR_SIZE - addr; + offset = 0; + } else { + pre = 0; + offset = addr - bufsec * SECTOR_SIZE; + } + + // Write buffered part first + uint32_t len_in_buf = len - pre; + len = 0; + if (len_in_buf > SECTOR_SIZE - offset) { + len = len_in_buf - (SECTOR_SIZE - offset); + len_in_buf = SECTOR_SIZE - offset; + } + memcpy(&buf[offset], &src[pre], len_in_buf); + self->flags |= 1; // Mark dirty + + // Write part before buffer sector + while (pre) { + int rest = pre & (SECTOR_SIZE - 1); + if (rest == 0) { + rest = SECTOR_SIZE; + } + int ret = mp_spiflash_write_part(self, addr, rest, src); + if (ret != 0) { + mp_spiflash_release_bus(self); + return ret; + } + src += rest; + addr += rest; + pre -= rest; + } + src += len_in_buf; + addr += len_in_buf; + + // Fall through to write remaining part + } + + uint32_t offset = addr & (SECTOR_SIZE - 1); + while (len) { + int rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; + } + int ret = mp_spiflash_write_part(self, addr, rest, src); if (ret != 0) { mp_spiflash_release_bus(self); return ret; } + len -= rest; + addr += rest; + src += rest; + offset = 0; } mp_spiflash_release_bus(self); - return 0; // success + return 0; } diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index cd96b16f3..03bad5296 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Damien P. George + * Copyright (c) 2016-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,14 +26,36 @@ #ifndef MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H #define MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H -#include "extmod/machine_spi.h" +#include "drivers/bus/spi.h" +#include "drivers/bus/qspi.h" + +enum { + MP_SPIFLASH_BUS_SPI, + MP_SPIFLASH_BUS_QSPI, +}; + +typedef struct _mp_spiflash_config_t { + uint32_t bus_kind; + union { + struct { + mp_hal_pin_obj_t cs; + void *data; + const mp_spi_proto_t *proto; + } u_spi; + struct { + void *data; + const mp_qspi_proto_t *proto; + } u_qspi; + } bus; +} mp_spiflash_config_t; typedef struct _mp_spiflash_t { - mp_hal_pin_obj_t cs; - mp_obj_base_t *spi; // object must have protocol pointing to mp_machine_spi_p_t struct + const mp_spiflash_config_t *config; + volatile uint32_t flags; } mp_spiflash_t; void mp_spiflash_init(mp_spiflash_t *self); +void mp_spiflash_flush(mp_spiflash_t *self); void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 75a0c501e..8f28b476e 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -14,10 +14,9 @@ Example usage on pyboard: Example usage on ESP8266: import machine, sdcard, os - sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15)) - os.umount() - os.VfsFat(sd, "") - os.listdir() + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) + os.mount(sd, '/sd') + os.listdir('/') """ @@ -46,6 +45,7 @@ class SDCard: self.cmdbuf = bytearray(6) self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) for i in range(512): self.dummybuf[i] = 0xff self.dummybuf_memoryview = memoryview(self.dummybuf) @@ -96,9 +96,14 @@ class SDCard: raise OSError("no response from SD card") csd = bytearray(16) self.readinto(csd) - if csd[0] & 0xc0 != 0x40: + if csd[0] & 0xc0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014 + elif csd[0] & 0xc0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4 + c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7 + self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2)) + else: raise OSError("SD card CSD format not supported") - self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014 #print('sectors', self.sectors) # CMD16: set block length to 512 bytes @@ -129,7 +134,7 @@ class SDCard: return raise OSError("timeout waiting for v2 card") - def cmd(self, cmd, arg, crc, final=0, release=True): + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): self.cs(0) # create and send the command @@ -142,9 +147,13 @@ class SDCard: buf[5] = crc self.spi.write(buf) + if skip1: + self.spi.readinto(self.tokenbuf, 0xff) + # wait for the response (response[7] == 0) for i in range(_CMD_TIMEOUT): - response = self.spi.read(1, 0xff)[0] + self.spi.readinto(self.tokenbuf, 0xff) + response = self.tokenbuf[0] if not (response & 0x80): # this could be a big-endian integer that we are getting here for j in range(final): @@ -159,27 +168,19 @@ class SDCard: self.spi.write(b'\xff') return -1 - def cmd_nodata(self, cmd): - self.spi.write(cmd) - self.spi.read(1, 0xff) # ignore stuff byte - for _ in range(_CMD_TIMEOUT): - if self.spi.read(1, 0xff)[0] == 0xff: - self.cs(1) - self.spi.write(b'\xff') - return 0 # OK - self.cs(1) - self.spi.write(b'\xff') - return 1 # timeout - def readinto(self, buf): self.cs(0) # read until start byte (0xff) - while self.spi.read(1, 0xff)[0] != 0xfe: - pass + while True: + self.spi.readinto(self.tokenbuf, 0xff) + if self.tokenbuf[0] == 0xfe: + break # read data - mv = self.dummybuf_memoryview[:len(buf)] + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[:len(buf)] self.spi.write_readinto(mv, buf) # read checksum @@ -226,26 +227,26 @@ class SDCard: return self.sectors def readblocks(self, block_num, buf): - nblocks, err = divmod(len(buf), 512) - assert nblocks and not err, 'Buffer length is invalid' + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, 'Buffer length is invalid' if nblocks == 1: # CMD17: set read address for single block if self.cmd(17, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO # receive the data self.readinto(buf) else: # CMD18: set read address for multiple blocks if self.cmd(18, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO offset = 0 mv = memoryview(buf) while nblocks: self.readinto(mv[offset : offset + 512]) offset += 512 nblocks -= 1 - return self.cmd_nodata(b'\x0c') # cmd 12 - return 0 + if self.cmd(12, 0, 0xff, skip1=True): + raise OSError(5) # EIO def writeblocks(self, block_num, buf): nblocks, err = divmod(len(buf), 512) @@ -253,14 +254,14 @@ class SDCard: if nblocks == 1: # CMD24: set write address for single block if self.cmd(24, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO # send the data self.write(_TOKEN_DATA, buf) else: # CMD25: set write address for first block if self.cmd(25, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO # send the data offset = 0 mv = memoryview(buf) @@ -269,4 +270,3 @@ class SDCard: offset += 512 nblocks -= 1 self.write_token(_TOKEN_STOP_TRAN) - return 0 diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib index a9b653517..6d6302050 100644 --- a/examples/embedding/Makefile.upylib +++ b/examples/embedding/Makefile.upylib @@ -13,7 +13,7 @@ include $(MPTOP)/py/py.mk INC += -I. INC += -I.. INC += -I$(MPTOP) -INC += -I$(MPTOP)/unix +INC += -I$(MPTOP)/ports/unix INC += -I$(BUILD) # compiler settings @@ -79,7 +79,7 @@ endif endif ifeq ($(MICROPY_USE_READLINE),1) -INC += -I../lib/mp-readline +INC += -I$(MPTOP)/lib/mp-readline CFLAGS_MOD += -DMICROPY_USE_READLINE=1 LIB_SRC_C_EXTRA += mp-readline/readline.c endif @@ -105,11 +105,11 @@ endif ifeq ($(MICROPY_PY_FFI),1) ifeq ($(MICROPY_STANDALONE),1) -LIBFFI_CFLAGS_MOD := -I$(shell ls -1d ../lib/libffi/build_dir/out/lib/libffi-*/include) +LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(MPTOP)/lib/libffi/build_dir/out/lib/libffi-*/include) ifeq ($(MICROPY_FORCE_32BIT),1) - LIBFFI_LDFLAGS_MOD = ../lib/libffi/build_dir/out/lib32/libffi.a + LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib32/libffi.a else - LIBFFI_LDFLAGS_MOD = ../lib/libffi/build_dir/out/lib/libffi.a + LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib/libffi.a endif else LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi) @@ -128,7 +128,7 @@ endif MAIN_C = main.c # source files -SRC_C = $(addprefix $(MPTOP)/unix/,\ +SRC_C = $(addprefix ports/unix/,\ $(MAIN_C) \ gccollect.c \ unix_mphal.c \ @@ -159,7 +159,6 @@ endif OBJ = $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(STMHAL_SRC_C:.c=.o)) # List of sources for qstr extraction SRC_QSTR += $(SRC_C) $(LIB_SRC_C) @@ -182,18 +181,18 @@ deplibs: libffi axtls # install-exec-recursive & install-data-am targets are used to avoid building # docs and depending on makeinfo libffi: - cd ../lib/libffi; git clean -d -x -f - cd ../lib/libffi; ./autogen.sh - mkdir -p ../lib/libffi/build_dir; cd ../lib/libffi/build_dir; \ + cd $(MPTOP)/lib/libffi; git clean -d -x -f + cd $(MPTOP)/lib/libffi; ./autogen.sh + mkdir -p $(MPTOP)/lib/libffi/build_dir; cd $(MPTOP)/lib/libffi/build_dir; \ ../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \ make install-exec-recursive; make -C include install-data-am -axtls: ../lib/axtls/README - cd ../lib/axtls; cp config/upyconfig config/.config - cd ../lib/axtls; make oldconfig -B - cd ../lib/axtls; make clean - cd ../lib/axtls; make all CC="$(CC)" LD="$(LD)" +axtls: $(MPTOP)/lib/axtls/README + cd $(MPTOP)/lib/axtls; cp config/upyconfig config/.config + cd $(MPTOP)/lib/axtls; make oldconfig -B + cd $(MPTOP)/lib/axtls; make clean + cd $(MPTOP)/lib/axtls; make all CC="$(CC)" LD="$(LD)" -../lib/axtls/README: +$(MPTOP)/lib/axtls/README: @echo "You cloned without --recursive, fetching submodules for you." - (cd ..; git submodule update --init --recursive) + (cd $(MPTOP); git submodule update --init --recursive) diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c index a67d294ba..f0c4896c2 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 e24e41eb3..db21e1cd3 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/modujson.c b/extmod/modujson.c index 6eeba4ed6..f731d7193 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -34,6 +34,16 @@ #if MICROPY_PY_UJSON +STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) { + if (!MP_OBJ_IS_OBJ(stream)) { + mp_raise_TypeError(NULL); + } + mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor}; + mp_obj_print_helper(&print, obj, PRINT_JSON); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump); + STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { vstr_t vstr; mp_print_t print; @@ -283,6 +293,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads); STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) }, + { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_ujson_dump_obj) }, { MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) }, { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) }, { MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) }, diff --git a/extmod/vfs.c b/extmod/vfs.c index 105a80a8d..0585de1c7 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -366,9 +366,7 @@ mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) { mp_obj_t dir_list = mp_obj_new_list(0, NULL); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { - mp_obj_t *items; - mp_obj_get_array_fixed_n(next, 3, &items); - mp_obj_list_append(dir_list, items[0]); + mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL)); } return dir_list; } diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 0076df262..5666a6b0c 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -47,6 +47,20 @@ #define mp_obj_fat_vfs_t fs_user_mount_t +mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) { + FILINFO fno; + assert(vfs != NULL); + FRESULT res = f_stat(&vfs->fatfs, path, &fno); + if (res == FR_OK) { + if ((fno.fattrib & AM_DIR) != 0) { + return MP_IMPORT_STAT_DIR; + } else { + return MP_IMPORT_STAT_FILE; + } + } + return MP_IMPORT_STAT_NO_EXIST; +} + STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); @@ -107,7 +121,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]); @@ -122,7 +181,17 @@ STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) { path = ""; } - return fat_vfs_ilistdir2(self, path, is_str_type); + // Create a new iterator object to list the dir + mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t); + iter->base.type = &mp_type_polymorph_iter; + iter->iternext = mp_vfs_fat_ilistdir_it_iternext; + iter->is_str = is_str_type; + FRESULT res = f_opendir(&self->fatfs, &iter->dir, path); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + return MP_OBJ_FROM_PTR(iter); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_ilistdir_obj, 1, 2, fat_vfs_ilistdir_func); diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index 688452973..da56a9077 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -57,9 +57,6 @@ extern const byte fresult_to_errno_table[20]; extern const mp_obj_type_t mp_fat_vfs_type; mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *path); -mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode); -MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); - -mp_obj_t fat_vfs_ilistdir2(struct _fs_user_mount_t *vfs, const char *path, bool is_str_type); +MP_DECLARE_CONST_FUN_OBJ_3(fat_vfs_open_obj); #endif // MICROPY_INCLUDED_EXTMOD_VFS_FAT_H diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index ff23c6b0c..712038f3e 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -36,6 +36,8 @@ #include "py/mphal.h" #include "py/runtime.h" +#include "py/binary.h" +#include "py/objarray.h" #include "lib/oofatfs/ff.h" #include "lib/oofatfs/diskio.h" #include "extmod/vfs_fat.h" @@ -126,8 +128,9 @@ DRESULT disk_read ( return RES_ERROR; } } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff}; vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->readblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), buff); + vfs->readblocks[3] = MP_OBJ_FROM_PTR(&ar); mp_call_method_n_kw(2, 0, vfs->readblocks); // TODO handle error return } @@ -162,8 +165,9 @@ DRESULT disk_write ( return RES_ERROR; } } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff}; vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), (void*)buff); + vfs->writeblocks[3] = MP_OBJ_FROM_PTR(&ar); mp_call_method_n_kw(2, 0, vfs->writeblocks); // TODO handle error return } diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 1fcbb253d..23e5aa10f 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -134,11 +134,7 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, break; case 1: // SEEK_CUR - if (s->offset != 0) { - *errcode = MP_EOPNOTSUPP; - return MP_STREAM_ERROR; - } - // no-operation + f_lseek(&self->fp, f_tell(&self->fp) + s->offset); break; case 2: // SEEK_END @@ -286,7 +282,7 @@ const mp_obj_type_t mp_type_textio = { }; // Factory function for I/O stream classes -mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) { +STATIC mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) { // TODO: analyze buffering args and instantiate appropriate type fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; @@ -295,5 +291,6 @@ mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) arg_vals[2].u_obj = mp_const_none; return file_open(self, &mp_type_textio, arg_vals); } +MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); #endif // MICROPY_VFS && MICROPY_VFS_FAT diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c deleted file mode 100644 index 1f90ac14c..000000000 --- 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)); - } 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/lib/stm32lib b/lib/stm32lib index d2bcfda54..90b996196 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit d2bcfda543d3b99361e44112aca929225bdcc07f +Subproject commit 90b9961963b625db0f2aabfe8e5e508b1f4fb7f1 diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 1e99aa649..0522de797 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -35,7 +35,7 @@ #include "py/gc.h" #include "py/frozenmod.h" #include "py/mphal.h" -#if defined(USE_DEVICE_MODE) +#if MICROPY_HW_ENABLE_USB #include "irq.h" #include "usb.h" #endif @@ -406,7 +406,7 @@ friendly_repl_reset: for (;;) { input_restart: - #if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB if (usb_vcp_is_enabled()) { // If the user gets to here and interrupts are disabled then // they'll never see the prompt, traceback etc. The USB REPL needs diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index bc98ba94a..678c56cf4 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 0fcd5d027..a515db80e 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/esp32/Makefile b/ports/esp32/Makefile index 2fa8c1c50..d2d6192b5 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -21,19 +21,23 @@ FLASH_FREQ ?= 40m FLASH_SIZE ?= 4MB CROSS_COMPILE ?= xtensa-esp32-elf- +ESPIDF_SUPHASH := 3ede9f011b50999b0560683f9419538c066dd09e + # paths to ESP IDF and its components ifeq ($(ESPIDF),) ifneq ($(IDF_PATH),) ESPIDF = $(IDF_PATH) else -$(error Please configure the ESPIDF variable) +$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.) +$(info See README.md for installation instructions.) +$(info Supported git hash: $(ESPIDF_SUPHASH)) +$(error ESPIDF not set) endif endif ESPCOMP = $(ESPIDF)/components ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py # verify the ESP IDF version -ESPIDF_SUPHASH := 2c95a77cf93781f296883d5dbafcdc18e4389656 ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H') ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH)) $(info ** WARNING **) @@ -86,6 +90,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include +INC_ESPCOMP += -I$(ESPCOMP)/app_update/include CFLAGS_BASE = -std=gnu99 -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H -DESP_PLATFORM CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP) @@ -143,11 +148,13 @@ SRC_C = \ network_lan.c \ modsocket.c \ modesp.c \ + modesp32.c \ moduhashlib.c \ espneopixel.c \ machine_hw_spi.c \ machine_wdt.c \ mpthreadport.c \ + machine_rtc.c \ $(SRC_MOD) EXTMOD_SRC_C = $(addprefix extmod/,\ @@ -188,6 +195,7 @@ LIB_SRC_C += \ endif DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ dht/dht.c \ ) @@ -247,6 +255,7 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\ dport_access.o \ wifi_init.o \ wifi_internal.o \ + sleep_modes.o \ ) ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\ @@ -329,9 +338,9 @@ ESPIDF_VFS_O = $(addprefix $(ESPCOMP)/vfs/,\ vfs.o \ ) -ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/,\ - library/cJSON.o \ - port/cJSON_Utils.o \ +ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/cJSON/,\ + cJSON.o \ + cJSON_Utils.o \ ) ESPIDF_LOG_O = $(addprefix $(ESPCOMP)/log/,\ @@ -351,6 +360,10 @@ ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\ app_trace.o \ ) +ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\ + esp_ota_ops.o \ + ) + ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\ time.o \ syscalls.o \ @@ -587,6 +600,7 @@ OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_MBEDTLS_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_XTENSA_DEBUG_MODULE_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_TCPIP_ADAPTER_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_TRACE_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_UPDATE_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O)) @@ -664,6 +678,7 @@ $(BUILD)/%.o: %.cpp $(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/esp32 -Wno-error=format BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\ + bootloader_support/src/bootloader_clock.o \ bootloader_support/src/bootloader_flash.o \ bootloader_support/src/bootloader_random.o \ bootloader_support/src/bootloader_sha.o \ diff --git a/ports/esp32/README.md b/ports/esp32/README.md index 5c0eb813d..ffd651c45 100644 --- a/ports/esp32/README.md +++ b/ports/esp32/README.md @@ -26,34 +26,28 @@ There are two main components that are needed to build the firmware: different to the compiler used by the ESP8266) - the Espressif IDF (IoT development framework, aka SDK) -Instructions for setting up both of these components are provided by the -ESP-IDF itself, which is found at https://github.com/espressif/esp-idf . -Follow the guide "Setting Up ESP-IDF", for Windows, Mac or Linux. You -only need to perform up to "Step 2" of the guide, by which stage you -should have installed the cross-compile and cloned the ESP-IDF repository. +The ESP-IDF changes quickly and MicroPython only supports a certain version. The +git hash of this version can be found by running `make` without a configured +`ESPIDF`. Then you can fetch only the given esp-idf using the following command: + + $ git clone https://github.com/espressif/esp-idf.git + $ git checkout + $ git submodule update --recursive + +The binary toolchain (binutils, gcc, etc.) can be installed using the following +guides: + + * [Linux installation](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) + * [MacOS installation](https://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html) + * [Windows installation](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html) If you are on a Windows machine then the [Windows Subsystem for Linux](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide) is the most efficient way to install the ESP32 toolchain and build the project. If you use WSL then follow the -[Linux guidelines](http://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) +[Linux guidelines](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html) for the ESP-IDF instead of the Windows ones. -Be advised that the ESP-IDF is still undergoing changes and only some -versions are supported. To find which build is compatible refer to the line -in the makefile containing the following: -``` -ESPIDF_SUPHASH := -``` -After finishing "Step 2" you can roll back your current build of -the ESP-IDF (and update the submodules accordingly) using: -``` -$ git checkout -$ git submodule update --recursive -``` -Note that you will get a warning when building the code if the ESP-IDF -version is incorrect. - The Espressif ESP-IDF instructions above only install pyserial for Python 2, so if you're running Python 3 or a non-system Python you'll also need to install `pyserial` (or `esptool`) so that the Makefile can flash the board @@ -64,7 +58,13 @@ $ pip install pyserial Once everything is set up you should have a functioning toolchain with prefix xtensa-esp32-elf- (or otherwise if you configured it differently) -as well as a copy of the ESP-IDF repository. +as well as a copy of the ESP-IDF repository. You will need to update your `PATH` +environment variable to include the ESP32 toolchain. For example, you can issue +the following commands on (at least) Linux: + + $ export PATH=$PATH:$HOME/esp/crosstool-NG/builds/xtensa-esp32-elf/bin + +You cam put this command in your `.profile` or `.bash_login`. You then need to set the `ESPIDF` environment/makefile variable to point to the root of the ESP-IDF repository. You can set the variable in your PATH, diff --git a/ports/esp32/esp32.custom_common.ld b/ports/esp32/esp32.custom_common.ld index eb1dee3c0..c9a61f018 100644 --- a/ports/esp32/esp32.custom_common.ld +++ b/ports/esp32/esp32.custom_common.ld @@ -89,7 +89,6 @@ SECTIONS *esp32/core_dump.o(.literal .text .literal.* .text.*) *app_trace/*(.literal .text .literal.* .text.*) *xtensa-debug-module/eri.o(.literal .text .literal.* .text.*) - *libphy.a:(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) *libsoc.a:(.literal .text .literal.* .text.*) *libhal.a:(.literal .text .literal.* .text.*) @@ -196,6 +195,13 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); + _thread_local_start = ABSOLUTE(.); + *(.tdata) + *(.tdata.*) + *(.tbss) + *(.tbss.*) + _thread_local_end = ABSOLUTE(.); + . = ALIGN(4); } >drom0_0_seg .flash.text : diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c index 493dff3f5..2a26d6bfb 100644 --- a/ports/esp32/machine_pin.c +++ b/ports/esp32/machine_pin.c @@ -35,6 +35,8 @@ #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; @@ -219,10 +221,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_ // pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING) STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_handler, ARG_trigger, ARG_hard }; + enum { ARG_handler, ARG_trigger, ARG_wake }; static const mp_arg_t allowed_args[] = { { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} }, + { MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -232,14 +235,48 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_ // configure irq mp_obj_t handler = args[ARG_handler].u_obj; uint32_t trigger = args[ARG_trigger].u_int; - if (handler == mp_const_none) { - handler = MP_OBJ_NULL; - trigger = 0; + mp_obj_t wake_obj = args[ARG_wake].u_obj; + + if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) { + mp_int_t wake; + if (mp_obj_get_int_maybe(wake_obj, &wake)) { + if (wake < 2 || wake > 7) { + mp_raise_ValueError("bad wake value"); + } + } else { + mp_raise_ValueError("bad wake value"); + } + + if (machine_rtc_config.wake_on_touch) { // not compatible + mp_raise_ValueError("no resources"); + } + + if (!RTC_IS_VALID_EXT_PIN(self->id)) { + mp_raise_ValueError("invalid pin for wake"); + } + + if (machine_rtc_config.ext0_pin == -1) { + machine_rtc_config.ext0_pin = self->id; + } else if (machine_rtc_config.ext0_pin != self->id) { + mp_raise_ValueError("no resources"); + } + + machine_rtc_config.ext0_level = trigger == GPIO_PIN_INTR_LOLEVEL ? 0 : 1; + machine_rtc_config.ext0_wake_types = wake; + } else { + if (machine_rtc_config.ext0_pin == self->id) { + machine_rtc_config.ext0_pin = -1; + } + + if (handler == mp_const_none) { + handler = MP_OBJ_NULL; + trigger = 0; + } + gpio_isr_handler_remove(self->id); + MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler; + gpio_set_intr_type(self->id, trigger); + gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self); } - gpio_isr_handler_remove(self->id); - MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler; - gpio_set_intr_type(self->id, trigger); - gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self); } // return the irq object @@ -261,6 +298,8 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN_ONLY) }, { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) }, { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) }, + { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) }, }; STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { diff --git a/ports/esp32/machine_rtc.c b/ports/esp32/machine_rtc.c new file mode 100644 index 000000000..a70134422 --- /dev/null +++ b/ports/esp32/machine_rtc.c @@ -0,0 +1,162 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 "Eric Poulsen" + * Copyright (c) 2017 "Tom Manning" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include +#include +#include "driver/gpio.h" + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "timeutils.h" +#include "modmachine.h" +#include "machine_rtc.h" + +typedef struct _machine_rtc_obj_t { + mp_obj_base_t base; +} machine_rtc_obj_t; + +#define MEM_MAGIC 0x75507921 +/* There is 8K of rtc_slow_memory, but some is used by the system software + If the USER_MAXLEN is set to high, the following compile error will happen: + region `rtc_slow_seg' overflowed by N bytes + The current system software allows almost 4096 to be used. + To avoid running into issues if the system software uses more, 2048 was picked as a max length +*/ +#define MEM_USER_MAXLEN 2048 +RTC_DATA_ATTR uint32_t rtc_user_mem_magic; +RTC_DATA_ATTR uint32_t rtc_user_mem_len; +RTC_DATA_ATTR uint8_t rtc_user_mem_data[MEM_USER_MAXLEN]; + +// singleton RTC object +STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}}; + +machine_rtc_config_t machine_rtc_config = { + .ext1_pins = 0, + .ext0_pin = -1 + }; + +STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 0, 0, false); + + // return constant object + return (mp_obj_t)&machine_rtc_obj; +} + +STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // Get time + + struct timeval tv; + + gettimeofday(&tv, NULL); + timeutils_struct_time_t tm; + + timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm); + + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(tv.tv_usec) + }; + + return mp_obj_new_tuple(8, tuple); + } else { + // Set time + + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 8, &items); + + struct timeval tv = {0}; + tv.tv_sec = timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6])); + settimeofday(&tv, NULL); + + return mp_const_none; + } +} +STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { + return machine_rtc_datetime_helper(n_args, args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime); + +STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) { + mp_obj_t args[2] = {self_in, date}; + machine_rtc_datetime_helper(2, args); + + if (rtc_user_mem_magic != MEM_MAGIC) { + rtc_user_mem_magic = MEM_MAGIC; + rtc_user_mem_len = 0; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init); + +STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // read RTC memory + uint32_t len = rtc_user_mem_len; + uint8_t rtcram[MEM_USER_MAXLEN]; + memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len); + return mp_obj_new_bytes(rtcram, len); + } else { + // write RTC memory + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + + if (bufinfo.len > MEM_USER_MAXLEN) { + mp_raise_ValueError("buffer too long"); + } + memcpy( (char *) rtc_user_mem_data, (char *) bufinfo.buf, bufinfo.len); + rtc_user_mem_len = bufinfo.len; + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_memory_obj, 1, 2, machine_rtc_memory); + +STATIC const mp_map_elem_t machine_rtc_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&machine_rtc_datetime_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&machine_rtc_datetime_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&machine_rtc_memory_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table); + +const mp_obj_type_t machine_rtc_type = { + { &mp_type_type }, + .name = MP_QSTR_RTC, + .make_new = machine_rtc_make_new, + .locals_dict = (mp_obj_t)&machine_rtc_locals_dict, +}; diff --git a/ports/esp32/machine_rtc.h b/ports/esp32/machine_rtc.h new file mode 100644 index 000000000..e34deb9be --- /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_uart.c b/ports/esp32/machine_uart.c index 0b303d424..26cbc88fc 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -187,7 +187,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, // get uart id mp_int_t uart_num = mp_obj_get_int(args[0]); - if (uart_num < 0 || uart_num > UART_NUM_MAX) { + if (uart_num < 0 || uart_num >= UART_NUM_MAX) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_num)); } @@ -297,7 +297,7 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait); - if (bytes_read < 0) { + if (bytes_read <= 0) { *errcode = MP_EAGAIN; return MP_STREAM_ERROR; } diff --git a/ports/esp32/machine_wdt.c b/ports/esp32/machine_wdt.c index 0389e8689..f0436056f 100644 --- a/ports/esp32/machine_wdt.c +++ b/ports/esp32/machine_wdt.c @@ -51,7 +51,7 @@ STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args switch (id) { case 0: - esp_task_wdt_feed(); + esp_task_wdt_add(NULL); return &wdt_default; default: mp_raise_ValueError(NULL); @@ -60,7 +60,7 @@ STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { (void)self_in; - esp_task_wdt_feed(); + esp_task_wdt_reset(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 091cbddc9..eebf183cd 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -53,11 +53,9 @@ #define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1) #define MP_TASK_STACK_SIZE (16 * 1024) #define MP_TASK_STACK_LEN (MP_TASK_STACK_SIZE / sizeof(StackType_t)) -#define MP_TASK_HEAP_SIZE (96 * 1024) STATIC StaticTask_t mp_task_tcb; STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8))); -STATIC uint8_t mp_task_heap[MP_TASK_HEAP_SIZE]; void mp_task(void *pvParameter) { volatile uint32_t sp = (uint32_t)get_sp(); @@ -66,11 +64,15 @@ void mp_task(void *pvParameter) { #endif uart_init(); + // Allocate the uPy heap using malloc and get the largest available region + size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + void *mp_task_heap = malloc(mp_task_heap_size); + soft_reset: // initialise the stack pointer for the main thread mp_stack_set_top((void *)sp); mp_stack_set_limit(MP_TASK_STACK_SIZE - 1024); - gc_init(mp_task_heap, mp_task_heap + sizeof(mp_task_heap)); + gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size); mp_init(); mp_obj_list_init(mp_sys_path, 0); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c new file mode 100644 index 000000000..6d18e0add --- /dev/null +++ b/ports/esp32/modesp32.c @@ -0,0 +1,138 @@ +/* + * 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_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 000000000..83532e052 --- /dev/null +++ b/ports/esp32/modesp32.h @@ -0,0 +1,29 @@ +#ifndef MICROPY_INCLUDED_ESP32_MODESP32_H +#define MICROPY_INCLUDED_ESP32_MODESP32_H + +#define RTC_VALID_EXT_PINS \ +( \ + (1ll << 0) | \ + (1ll << 2) | \ + (1ll << 4) | \ + (1ll << 12) | \ + (1ll << 13) | \ + (1ll << 14) | \ + (1ll << 15) | \ + (1ll << 25) | \ + (1ll << 26) | \ + (1ll << 27) | \ + (1ll << 32) | \ + (1ll << 33) | \ + (1ll << 34) | \ + (1ll << 35) | \ + (1ll << 36) | \ + (1ll << 37) | \ + (1ll << 38) | \ + (1ll << 39) \ +) + +#define RTC_LAST_EXT_PIN 39 +#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS) + +#endif // MICROPY_INCLUDED_ESP32_MODESP32_H diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 32c9c5ad5..2d59e137e 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -33,7 +33,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "rom/ets_sys.h" +#include "rom/rtc.h" #include "esp_system.h" +#include "driver/touch_pad.h" #include "py/obj.h" #include "py/runtime.h" @@ -43,9 +45,18 @@ #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 @@ -64,6 +75,104 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq); +STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + enum {ARG_sleep_ms}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_sleep_ms, MP_ARG_INT, { .u_int = 0 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + + mp_int_t expiry = args[ARG_sleep_ms].u_int; + + if (expiry != 0) { + esp_sleep_enable_timer_wakeup(expiry * 1000); + } + + if (machine_rtc_config.ext0_pin != -1 && (machine_rtc_config.ext0_wake_types & wake_type)) { + esp_sleep_enable_ext0_wakeup(machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? 1 : 0); + } + + if (machine_rtc_config.ext1_pins != 0) { + esp_sleep_enable_ext1_wakeup( + machine_rtc_config.ext1_pins, + machine_rtc_config.ext1_level ? ESP_EXT1_WAKEUP_ANY_HIGH : ESP_EXT1_WAKEUP_ALL_LOW); + } + + if (machine_rtc_config.wake_on_touch) { + if (esp_sleep_enable_touchpad_wakeup() != ESP_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "esp_sleep_enable_touchpad_wakeup() failed")); + } + } + + switch(wake_type) { + case MACHINE_WAKE_SLEEP: + esp_light_sleep_start(); + break; + case MACHINE_WAKE_DEEPSLEEP: + esp_deep_sleep_start(); + break; + } + return mp_const_none; +} + +STATIC mp_obj_t machine_sleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "light sleep not available for this version of ESP-IDF")); + return machine_sleep_helper(MACHINE_WAKE_SLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_sleep_obj, 0, machine_sleep); + +STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return machine_sleep_helper(MACHINE_WAKE_DEEPSLEEP, n_args, pos_args, kw_args); +}; +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_deepsleep_obj, 0, machine_deepsleep); + +STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + switch(rtc_get_reset_reason(0)) { + case POWERON_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_PWRON_RESET); + break; + case SW_RESET: + case SW_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_SOFT_RESET); + break; + case OWDT_RESET: + case TG0WDT_SYS_RESET: + case TG1WDT_SYS_RESET: + case RTCWDT_SYS_RESET: + case RTCWDT_BROWN_OUT_RESET: + case RTCWDT_CPU_RESET: + case RTCWDT_RTC_RESET: + case TGWDT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_WDT_RESET); + break; + + case DEEPSLEEP_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_DEEPSLEEP_RESET); + break; + + case EXT_CPU_RESET: + return MP_OBJ_NEW_SMALL_INT(MP_HARD_RESET); + break; + + case NO_MEAN: + case SDIO_RESET: + case INTRUSION_RESET: + default: + return MP_OBJ_NEW_SMALL_INT(0); + break; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_reset_cause_obj, 0, machine_reset_cause); + +STATIC mp_obj_t machine_wake_reason(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return MP_OBJ_NEW_SMALL_INT(esp_sleep_get_wakeup_cause()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_wake_reason_obj, 0, machine_wake_reason); + STATIC mp_obj_t machine_reset(void) { esp_restart(); return mp_const_none; @@ -106,6 +215,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, @@ -115,6 +226,10 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) }, + + // wake abilities + { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(MACHINE_WAKE_SLEEP) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) }, { MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) }, @@ -122,8 +237,26 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) }, + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&mp_machine_soft_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, + + // Reset reasons + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(MP_HARD_RESET) }, + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(MP_WDT_RESET) }, + { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(MP_DEEPSLEEP_RESET) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(MP_SOFT_RESET) }, + + // Wake reasons + { MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) }, + { MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT0_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) }, + { MP_ROM_QSTR(MP_QSTR_EXT1_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT1) }, + { MP_ROM_QSTR(MP_QSTR_TIMER_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TIMER) }, + { MP_ROM_QSTR(MP_QSTR_TOUCHPAD_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TOUCHPAD) }, + { MP_ROM_QSTR(MP_QSTR_ULP_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_ULP) }, }; STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index 58229007d..c8513a471 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -3,6 +3,12 @@ #include "py/obj.h" +typedef enum { + //MACHINE_WAKE_IDLE=0x01, + MACHINE_WAKE_SLEEP=0x02, + MACHINE_WAKE_DEEPSLEEP=0x04 +} wake_type_t; + extern const mp_obj_type_t machine_timer_type; extern const mp_obj_type_t machine_wdt_type; extern const mp_obj_type_t machine_pin_type; @@ -12,6 +18,7 @@ extern const mp_obj_type_t machine_dac_type; extern const mp_obj_type_t machine_pwm_type; extern const mp_obj_type_t machine_hw_spi_type; extern const mp_obj_type_t machine_uart_type; +extern const mp_obj_type_t machine_rtc_type; void machine_pins_init(void); void machine_pins_deinit(void); diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 3c348fc15..ef5292be3 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -275,11 +275,36 @@ STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); -STATIC mp_obj_t esp_status(mp_obj_t self_in) { +STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + // no arguments: return None until link status is implemented + return mp_const_none; + } + + // one argument: return status based on query parameter + switch ((uintptr_t)args[1]) { + case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): { + // return list of connected stations, only if in soft-AP mode + require_if(args[0], WIFI_IF_AP); + wifi_sta_list_t station_list; + ESP_EXCEPTIONS(esp_wifi_ap_get_sta_list(&station_list)); + wifi_sta_info_t *stations = (wifi_sta_info_t*)station_list.sta; + mp_obj_t list = mp_obj_new_list(0, NULL); + for (int i = 0; i < station_list.num; ++i) { + mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL); + t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac)); + mp_obj_list_append(list, t); + } + return list; + } + + default: + mp_raise_ValueError("unknown status param"); + } + return mp_const_none; } - -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status); STATIC mp_obj_t esp_scan(mp_obj_t self_in) { // check that STA mode is active @@ -445,6 +470,11 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); break; } + case QS(MP_QSTR_dhcp_hostname): { + const char *s = mp_obj_str_get_str(kwargs->table[i].value); + ESP_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id, s)); + break; + } default: goto unknown; } @@ -494,6 +524,12 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs req_if = WIFI_IF_AP; val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); break; + case QS(MP_QSTR_dhcp_hostname): { + const char *s; + ESP_EXCEPTIONS(tcpip_adapter_get_hostname(self->if_id, &s)); + val = mp_obj_new_str(s, strlen(s)); + break; + } default: goto unknown; } diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index cba34d76c..31d153964 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -520,9 +520,11 @@ STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket); -STATIC mp_obj_t esp_socket_getaddrinfo(const mp_obj_t host, const mp_obj_t port) { +STATIC mp_obj_t esp_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) { + // TODO support additional args beyond the first two + struct addrinfo *res = NULL; - _socket_getaddrinfo2(host, port, &res); + _socket_getaddrinfo2(args[0], args[1], &res); mp_obj_t ret_list = mp_obj_new_list(0, NULL); for (struct addrinfo *resi = res; resi; resi = resi->ai_next) { @@ -552,7 +554,7 @@ STATIC mp_obj_t esp_socket_getaddrinfo(const mp_obj_t host, const mp_obj_t port) if (res) lwip_freeaddrinfo(res); return ret_list; } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_getaddrinfo_obj, esp_socket_getaddrinfo); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_socket_getaddrinfo_obj, 2, 6, esp_socket_getaddrinfo); STATIC mp_obj_t esp_socket_initialize() { static int initialized = 0; diff --git a/ports/esp32/modules/dht.py b/ports/esp32/modules/dht.py index b6acf2853..2aa2f5cbf 120000 --- a/ports/esp32/modules/dht.py +++ b/ports/esp32/modules/dht.py @@ -1 +1 @@ -../../esp8266/modules/dht.py \ No newline at end of file +../../../drivers/dht/dht.py \ No newline at end of file diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 69d17fd81..80594b114 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -90,6 +90,7 @@ #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_ATTRTUPLE (1) #define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) @@ -134,8 +135,8 @@ #define MICROPY_PY_MACHINE_SPI_MSB (0) #define MICROPY_PY_MACHINE_SPI_LSB (1) #define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new -#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0) -#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly #define MICROPY_PY_USSL (1) #define MICROPY_SSL_MBEDTLS (1) #define MICROPY_PY_USSL_FINALISER (1) @@ -162,6 +163,7 @@ // extra built in modules to add to the list of known ones extern const struct _mp_obj_module_t esp_module; +extern const struct _mp_obj_module_t esp32_module; extern const struct _mp_obj_module_t utime_module; extern const struct _mp_obj_module_t uos_module; extern const struct _mp_obj_module_t mp_module_usocket; @@ -171,6 +173,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_esp32), (mp_obj_t)&esp32_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \ diff --git a/ports/esp32/sdkconfig.h b/ports/esp32/sdkconfig.h index 7fcbb7c01..113c0395f 100644 --- a/ports/esp32/sdkconfig.h +++ b/ports/esp32/sdkconfig.h @@ -1,3 +1,8 @@ +/* Start bootloader config */ +#define CONFIG_FLASHMODE_DIO 1 +#define CONFIG_ESPTOOLPY_FLASHFREQ_40M 1 +/* End bootloader config */ + #define CONFIG_TRACEMEM_RESERVE_DRAM 0x0 #define CONFIG_BT_RESERVE_DRAM 0x0 #define CONFIG_ULP_COPROC_RESERVE_MEM 0 @@ -23,7 +28,7 @@ #define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240 #define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1 #define CONFIG_ESP32_DEBUG_OCDAWARE 1 -#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 0 +#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000 #define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1 #define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1 #define CONFIG_ESP32_WIFI_AMPDU_ENABLED 1 @@ -104,6 +109,9 @@ #define CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX 0 #define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1 #define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1 +#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60 +#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8 +#define CONFIG_LWIP_MAX_ACTIVE_TCP 16 #define CONFIG_LWIP_MAX_SOCKETS 8 #define CONFIG_LWIP_SO_REUSE 1 #define CONFIG_LWIP_ETHARP_TRUST_IP_MAC 1 diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 95236a8d9..716f18d6a 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -130,6 +130,7 @@ LIB_SRC_C += \ endif DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ dht/dht.c \ ) @@ -143,7 +144,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) -#OBJ += $(BUILD)/pins_$(BOARD).o # List of sources for qstr extraction SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C) @@ -195,32 +195,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 99e256016..f4dddd1ca 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 ``` diff --git a/ports/esp8266/esp8266_common.ld b/ports/esp8266/esp8266_common.ld index 08da02869..6b7eba56a 100644 --- a/ports/esp8266/esp8266_common.ld +++ b/ports/esp8266/esp8266_common.ld @@ -135,6 +135,7 @@ SECTIONS *lib/netutils/*.o*(.literal*, .text*) *lib/timeutils/*.o*(.literal*, .text*) *lib/utils/*.o*(.literal*, .text*) + *drivers/bus/*.o(.literal* .text*) build/main.o(.literal* .text*) *gccollect.o(.literal* .text*) diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h index 194e56f64..940ca4727 100644 --- a/ports/esp8266/esp_mphal.h +++ b/ports/esp8266/esp_mphal.h @@ -86,7 +86,7 @@ void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin); } while (0) #define mp_hal_pin_od_high(p) do { \ if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); } \ - else { gpio_output_set(1 << (p), 0, 1 << (p), 0); } \ + else { gpio_output_set(0, 0, 0, 1 << (p)); /* set as input to avoid glitches */ } \ } while (0) #define mp_hal_pin_read(p) pin_get(p) #define mp_hal_pin_write(p, v) pin_set((p), (v)) diff --git a/ports/esp8266/esppwm.c b/ports/esp8266/esppwm.c index f1d7060df..33eaf3b9a 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;iif_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; diff --git a/ports/esp8266/modules/dht.py b/ports/esp8266/modules/dht.py deleted file mode 100644 index 9a69e7e07..000000000 --- a/ports/esp8266/modules/dht.py +++ /dev/null @@ -1,32 +0,0 @@ -# DHT11/DHT22 driver for MicroPython on ESP8266 -# MIT license; Copyright (c) 2016 Damien P. George - -import esp - -class DHTBase: - def __init__(self, pin): - self.pin = pin - self.buf = bytearray(5) - - def measure(self): - buf = self.buf - esp.dht_readinto(self.pin, buf) - if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: - raise Exception("checksum error") - -class DHT11(DHTBase): - def humidity(self): - return self.buf[0] - - def temperature(self): - return self.buf[2] - -class DHT22(DHTBase): - def humidity(self): - return (self.buf[0] << 8 | self.buf[1]) * 0.1 - - def temperature(self): - t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1 - if self.buf[2] & 0x80: - t = -t - return t diff --git a/ports/esp8266/modules/dht.py b/ports/esp8266/modules/dht.py new file mode 120000 index 000000000..2aa2f5cbf --- /dev/null +++ b/ports/esp8266/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index c45ed92c7..fc992a4b1 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -49,6 +49,7 @@ #define MICROPY_PY_ARRAY (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH (1) #define MICROPY_PY_CMATH (0) diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c index 6c1f9e095..ec944a97c 100644 --- a/ports/esp8266/uart.c +++ b/ports/esp8266/uart.c @@ -276,7 +276,7 @@ void uart_task_handler(os_event_t *evt) { int c, ret = 0; while ((c = ringbuf_get(&input_buf)) >= 0) { - if (c == interrupt_char) { + if (c == mp_interrupt_char) { mp_keyboard_interrupt(); } ret = pyexec_event_repl_process_char(c); diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile index ae295d655..64ad3cc0b 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 14b8c00a3..356fc4b3e 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/stm32/Makefile b/ports/stm32/Makefile index 68b007471..0e7f7f71a 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -37,6 +37,7 @@ DEVICE=0483:df11 STFLASH ?= st-flash OPENOCD ?= openocd OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg +STARTUP_FILE ?= boards/startup_stm32$(MCU_SERIES).o CROSS_COMPILE = arm-none-eabi- @@ -53,16 +54,17 @@ INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc CFLAGS_CORTEX_M = -mthumb # Select hardware floating-point support -ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx)) +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx STM32H743xx)) CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard else CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard endif # Options for particular MCU series -CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_F4 -CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 -DMCU_SERIES_F7 -CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_L4 +CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 +CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 +CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA) CFLAGS += -D$(CMSIS_MCU) @@ -70,6 +72,7 @@ CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES)) CFLAGS += $(COPT) CFLAGS += -Iboards/$(BOARD) CFLAGS += -DSTM32_HAL_H='' +CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR) ifeq ($(MICROPY_FLOAT_IMPL),double) CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE @@ -78,7 +81,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. @@ -185,7 +188,10 @@ EXTMOD_SRC_C = $(addprefix extmod/,\ ) DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ + bus/softqspi.c \ memory/spiflash.c \ + dht/dht.c \ ) SRC_C = \ @@ -212,6 +218,7 @@ SRC_C = \ dma.c \ i2c.c \ spi.c \ + qspi.c \ uart.c \ can.c \ usb.c \ @@ -231,6 +238,8 @@ SRC_C = \ rng.c \ rtc.c \ flash.c \ + flashbdev.c \ + spibdev.c \ storage.c \ sdcard.c \ fatfs_port.c \ @@ -242,14 +251,14 @@ SRC_C = \ $(wildcard boards/$(BOARD)/*.c) SRC_O = \ - startup_stm32.o \ + $(STARTUP_FILE) \ + resethandler.o \ gchelper.o \ 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 \ @@ -264,7 +273,6 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ hal_pwr_ex.c \ hal_rcc.c \ hal_rcc_ex.c \ - hal_rng.c \ hal_rtc.c \ hal_rtc_ex.c \ hal_sd.c \ @@ -276,6 +284,12 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\ ll_usb.c \ ) +ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx)) + SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c) +else + SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c) +endif + SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\ core/src/usbd_core.c \ core/src/usbd_ctlreq.c \ @@ -375,27 +389,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) @@ -444,7 +481,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 @@ -459,22 +496,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/accel.c b/ports/stm32/accel.c index 7b36e2082..ec7672782 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" @@ -57,8 +56,8 @@ void accel_init(void) { // PB5 is connected to AVDD; pull high to enable MMA accel device - mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD - mp_hal_pin_output(&MICROPY_HW_MMA_AVDD_PIN); + mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD + mp_hal_pin_output(MICROPY_HW_MMA_AVDD_PIN); } STATIC void accel_start(void) { @@ -74,9 +73,9 @@ STATIC void accel_start(void) { i2c_init(&I2CHandle1); // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again - mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off + mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off mp_hal_delay_ms(30); - mp_hal_pin_high(&MICROPY_HW_MMA_AVDD_PIN); // turn on + mp_hal_pin_high(MICROPY_HW_MMA_AVDD_PIN); // turn on mp_hal_delay_ms(30); HAL_StatusTypeDef status; diff --git a/ports/stm32/accel.h b/ports/stm32/accel.h index fc35f7775..1fea1249c 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 9a0dc56a3..3f38fa2ca 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 /// @@ -51,10 +52,10 @@ /* ADC defintions */ #define ADCx (ADC1) -#define ADCx_CLK_ENABLE __ADC1_CLK_ENABLE +#define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE #define ADC_NUM_CHANNELS (19) -#if defined(MCU_SERIES_F4) +#if defined(STM32F4) #define ADC_FIRST_GPIO_CHANNEL (0) #define ADC_LAST_GPIO_CHANNEL (15) @@ -62,15 +63,21 @@ #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(STM32L4) #define ADC_FIRST_GPIO_CHANNEL (1) #define ADC_LAST_GPIO_CHANNEL (16) @@ -91,6 +98,8 @@ #define VBAT_DIV (2) #elif defined(STM32F427xx) || defined(STM32F429xx) || \ defined(STM32F437xx) || defined(STM32F439xx) || \ + defined(STM32F722xx) || defined(STM32F723xx) || \ + defined(STM32F732xx) || defined(STM32F733xx) || \ defined(STM32F746xx) || defined(STM32F767xx) || \ defined(STM32F769xx) || defined(STM32F446xx) #define VBAT_DIV (4) @@ -117,7 +126,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 +137,9 @@ static inline uint32_t adc_get_internal_channel(uint32_t channel) { } STATIC bool is_adcx_channel(int channel) { -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) return IS_ADC_CHANNEL(channel); -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) ADC_HandleTypeDef handle; handle.Instance = ADCx; return IS_ADC_CHANNEL(&handle, channel); @@ -141,9 +150,9 @@ STATIC bool is_adcx_channel(int channel) { STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { uint32_t tickstart = HAL_GetTick(); -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) { -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) { #else #error Unsupported processor @@ -155,9 +164,9 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { } STATIC void adcx_clock_enable(void) { -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) ADCx_CLK_ENABLE(); -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) __HAL_RCC_ADC_CLK_ENABLE(); #else #error Unsupported processor @@ -176,9 +185,9 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { mp_hal_gpio_clock_enable(pin->gpio); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = pin->pin_mask; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; #else #error Unsupported processor @@ -199,12 +208,12 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { adcHandle->Init.NbrOfConversion = 1; adcHandle->Init.DMAContinuousRequests = DISABLE; adcHandle->Init.Resolution = ADC_RESOLUTION_12B; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; adcHandle->Init.ScanConvMode = DISABLE; adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; adcHandle->Init.EOCSelection = DISABLE; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV; @@ -219,7 +228,7 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { HAL_ADC_Init(adcHandle); -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) ADC_MultiModeTypeDef multimode; multimode.Mode = ADC_MODE_INDEPENDENT; if (HAL_ADCEx_MultiModeConfigChannel(adcHandle, &multimode) != HAL_OK) @@ -234,9 +243,9 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.Channel = channel; sConfig.Rank = 1; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; @@ -253,7 +262,7 @@ STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) { HAL_ADC_Start(adcHandle); if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK - && (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_EOC_REG) == HAL_ADC_STATE_EOC_REG) { + && (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC) { rawValue = HAL_ADC_GetValue(adcHandle); } HAL_ADC_Stop(adcHandle); @@ -401,9 +410,9 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ HAL_ADC_Start(&self->handle); } else { // for subsequent samples we can just set the "start sample" bit -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) SET_BIT(ADCx->CR, ADC_CR_ADSTART); #else #error Unsupported processor @@ -503,11 +512,11 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m adcHandle->Init.NbrOfConversion = 1; adcHandle->Init.DMAContinuousRequests = DISABLE; adcHandle->Init.EOCSelection = DISABLE; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; adcHandle->Init.ScanConvMode = DISABLE; adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1; @@ -527,7 +536,7 @@ uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t chan } int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { - uint32_t res_reg = __HAL_ADC_GET_RESOLUTION(adcHandle); + uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle); switch (res_reg) { case ADC_RESOLUTION_6B: return 6; @@ -568,7 +577,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 +684,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 c90e6b343..4ae6022bc 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 77f029c00..3ab3d5fa1 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 1ba61a327..55e443e91 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 9348e0679..6bfb28118 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 e668ba4e1..fdc7c0120 100644 --- a/ports/stm32/boards/CERB40/mpconfigboard.h +++ b/ports/stm32/boards/CERB40/mpconfigboard.h @@ -1,18 +1,12 @@ #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) @@ -61,5 +55,6 @@ // The Cerb40 has No SDCard // USB config +#define MICROPY_HW_USB_FS (1) //#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) //#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/CERB40/mpconfigboard.mk b/ports/stm32/boards/CERB40/mpconfigboard.mk index 5734c6690..40972b385 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/stm32f4xx_hal_conf.h b/ports/stm32/boards/CERB40/stm32f4xx_hal_conf.h index d6aca705c..e71ba3369 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 d065180d8..53c7f3cd5 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 d531a594a..16cacc089 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 11a396b73..d27e2e9ef 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 8eaa36747..2e73d3ec8 100644 --- a/ports/stm32/boards/HYDRABUS/mpconfigboard.h +++ b/ports/stm32/boards/HYDRABUS/mpconfigboard.h @@ -4,15 +4,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 (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) @@ -76,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 5734c6690..40972b385 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 d3df51c10..daf9b63ce 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 72f920842..67ccf23cc 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 42b862fcf..d27c2e66e 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 a1304b655..2adc98f0b 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 9348e0679..6bfb28118 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 085034b2d..53df72503 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 9586ae4e5..312576756 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 5734c6690..40972b385 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/stm32f4xx_hal_conf.h b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h index 42c2c4e9b..4cb5a83e4 100644 --- a/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NETDUINO_PLUS_2/stm32f4xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F401RE/mpconfigboard.mk index eb391bed7..4c3022f54 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 f4db4cb63..daf9b63ce 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 71b3b19d6..df9506522 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 0c424888f..8f0b66381 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 608beef67..ae7f82225 100644 --- a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h @@ -3,16 +3,10 @@ #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) @@ -79,5 +73,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.mk index 1bbf808b6..d19a35c31 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 d121b18c5..5b5a8a3e4 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 e1ec6d57c..64a80e992 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 487ca009f..245fb9a06 100644 --- a/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F446RE/stm32f4xx_hal_conf.h @@ -46,10 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -// This board doesn't really have USB, but the stm32 codebase doesn't build -// without some USB defined, so we leave this on for now. -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h index c5b84938c..42beb4d9b 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.h @@ -8,16 +8,11 @@ #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) // HSE is 8MHz // VCOClock = HSE * PLLN / PLLM = 8 MHz * 216 / 4 = 432 MHz @@ -72,5 +67,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk index 7c6bc4584..160218fd3 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/mpconfigboard.mk +++ b/ports/stm32/boards/NUCLEO_F746ZG/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/NUCLEO_F746ZG/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h index e1aa4578d..a019ee4ce 100644 --- a/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h +++ b/ports/stm32/boards/NUCLEO_F746ZG/stm32f7xx_hal_conf.h @@ -46,8 +46,6 @@ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ -#define USE_USB_FS - /* ########################## Module Selection ############################## */ /** * @brief This is the list of modules to be used in the HAL driver diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h index 8952bce82..4f9d41f1b 100644 --- a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h +++ b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.h @@ -8,16 +8,11 @@ #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) // HSE is 25MHz // VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz @@ -72,5 +67,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk b/ports/stm32/boards/NUCLEO_F767ZI/mpconfigboard.mk index ba28a16e1..b79ee7da2 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 897b1473e..84506649e 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 diff --git a/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h b/ports/stm32/boards/NUCLEO_F767ZI/stm32f7xx_hal_conf.h index e1aa4578d..a019ee4ce 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 000000000..1a6006c28 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/board_init.c @@ -0,0 +1,15 @@ +#include STM32_HAL_H + +void NUCLEO_H743ZI_board_early_init(void) { + GPIO_InitTypeDef GPIO_InitStructure; + + __HAL_RCC_GPIOG_CLK_ENABLE(); + + // Turn off the USB switch + GPIO_InitStructure.Pin = GPIO_PIN_6; + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_PULLDOWN; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET); +} diff --git a/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h new file mode 100644 index 000000000..7aea8b06a --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/mpconfigboard.h @@ -0,0 +1,63 @@ +#define MICROPY_HW_BOARD_NAME "NUCLEO_H743ZI" +#define MICROPY_HW_MCU_NAME "STM32H743" + +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_ADC (0) +#define MICROPY_HW_ENABLE_USB (1) +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_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 000000000..4d3455441 --- /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 000000000..92627ba95 --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/pins.csv @@ -0,0 +1,61 @@ +A0,PA0 +A1,PF10 +A2,PF9 +A3,PF8 +A4,PF7 +A5,PF6 +D0,PC7 +D1,PC6 +D2,PG6 +D3,PB4 +D4,PG7 +D5,PA8 +D6,PH6 +D7,PI3 +D8,PI2 +D9,PA15 +D10,PI0 +D11,PB15 +D12,PB14 +D13,PI1 +D14,PB9 +D15,PB8 +LED1,PB0 +LED2,PB7 +LED3,PB14 +SW,PC13 +TP1,PH2 +TP2,PI8 +TP3,PH15 +AUDIO_INT,PD6 +AUDIO_SDA,PH8 +AUDIO_SCL,PH7 +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 000000000..19f9563ab --- /dev/null +++ b/ports/stm32/boards/NUCLEO_H743ZI/stm32h7xx_hal_conf.h @@ -0,0 +1,434 @@ +/** + ****************************************************************************** + * @file stm32h7xx_hal_conf_template.h + * @author MCD Application Team + * @version V1.2.0 + * @date 29-December-2017 + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32h7xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32H7xx_HAL_CONF_H +#define __STM32H7xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CEC_MODULE_ENABLED +#define HAL_COMP_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_CRYP_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DCMI_MODULE_ENABLED +#define HAL_DFSDM_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_DMA2D_MODULE_ENABLED +#define HAL_ETH_MODULE_ENABLED +#define HAL_FDCAN_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_HASH_MODULE_ENABLED +#define HAL_HCD_MODULE_ENABLED +#define HAL_HRTIM_MODULE_ENABLED +#define HAL_HSEM_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +#define HAL_IRDA_MODULE_ENABLED +#define HAL_IWDG_MODULE_ENABLED +#define HAL_JPEG_MODULE_ENABLED +#define HAL_LPTIM_MODULE_ENABLED +#define HAL_LTDC_MODULE_ENABLED +#define HAL_MDIOS_MODULE_ENABLED +#define HAL_MDMA_MODULE_ENABLED +#define HAL_MMC_MODULE_ENABLED +#define HAL_NAND_MODULE_ENABLED +#define HAL_NOR_MODULE_ENABLED +#define HAL_OPAMP_MODULE_ENABLED +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_QSPI_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SAI_MODULE_ENABLED +#define HAL_SD_MODULE_ENABLED +#define HAL_SDRAM_MODULE_ENABLED +#define HAL_SMARTCARD_MODULE_ENABLED +#define HAL_SMBUS_MODULE_ENABLED +#define HAL_SPDIFRX_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_SRAM_MODULE_ENABLED +#define HAL_SWPMI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) +#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal oscillator (CSI) default value. + * This value is the default CSI value after Reset. + */ +#if !defined (CSI_VALUE) + #define CSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* CSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)64000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External clock in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x0F) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define USE_SD_TRANSCEIVER 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 f2474619f..0d5dab394 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 abb4a3570..38ae5af21 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 9348e0679..6bfb28118 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 86dfd1166..1bdb25a9e 100644 --- a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h +++ b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.h @@ -4,15 +4,11 @@ #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) @@ -74,5 +70,6 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk b/ports/stm32/boards/OLIMEX_E407/mpconfigboard.mk index ece09caa1..b154dcfba 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/stm32f4xx_hal_conf.h b/ports/stm32/boards/OLIMEX_E407/stm32f4xx_hal_conf.h index b84b0a892..24cc9228b 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 090ba4cf1..60a6980aa 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 71b3b19d6..df9506522 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 4ee8e7276..4e96f785a 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 c06022a34..5d158e6b1 100644 --- a/ports/stm32/boards/PYBV10/mpconfigboard.h +++ b/ports/stm32/boards/PYBV10/mpconfigboard.h @@ -5,14 +5,13 @@ #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) @@ -92,6 +91,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/PYBV10/mpconfigboard.mk b/ports/stm32/boards/PYBV10/mpconfigboard.mk index 5734c6690..40972b385 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 3d9252264..4f18ac81e 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 c69e52cc5..71ff52848 100644 --- a/ports/stm32/boards/PYBV11/mpconfigboard.h +++ b/ports/stm32/boards/PYBV11/mpconfigboard.h @@ -5,14 +5,13 @@ #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) @@ -92,6 +91,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/PYBV11/mpconfigboard.mk b/ports/stm32/boards/PYBV11/mpconfigboard.mk index 5734c6690..40972b385 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 b84b0a892..24cc9228b 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 1f49af4da..d2e7dbe20 100644 --- a/ports/stm32/boards/PYBV3/mpconfigboard.h +++ b/ports/stm32/boards/PYBV3/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 (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) @@ -82,6 +80,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_SET) // USB VBUS detect pin +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) // MMA accelerometer config diff --git a/ports/stm32/boards/PYBV3/mpconfigboard.mk b/ports/stm32/boards/PYBV3/mpconfigboard.mk index 5734c6690..40972b385 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/stm32f4xx_hal_conf.h b/ports/stm32/boards/PYBV3/stm32f4xx_hal_conf.h index d3df51c10..daf9b63ce 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 2a4829c3e..c6d9ad9ac 100644 --- a/ports/stm32/boards/PYBV4/mpconfigboard.h +++ b/ports/stm32/boards/PYBV4/mpconfigboard.h @@ -5,14 +5,13 @@ #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) @@ -89,6 +88,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/PYBV4/mpconfigboard.mk b/ports/stm32/boards/PYBV4/mpconfigboard.mk index 5734c6690..40972b385 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 d3df51c10..daf9b63ce 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 1488cd764..13172333b 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 71b3b19d6..df9506522 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/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F411DISC/stm32f4xx_hal_conf.h index 921cbe5fe..8f0b66381 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 fc0702025..01713f7f8 100644 --- a/ports/stm32/boards/STM32F429DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F429DISC/mpconfigboard.h @@ -3,16 +3,10 @@ #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) @@ -69,5 +63,7 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_B13) #define MICROPY_HW_USB_OTG_ID_PIN (pin_B12) diff --git a/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F429DISC/mpconfigboard.mk index 1bbf808b6..d19a35c31 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 4f5962dcb..5b5a8a3e4 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 eca79bf58..66bfcf2ec 100644 --- a/ports/stm32/boards/STM32F439/mpconfigboard.h +++ b/ports/stm32/boards/STM32F439/mpconfigboard.h @@ -1,18 +1,13 @@ #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 +22,9 @@ #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) //divide PLL clock by this to get core clock #define MICROPY_HW_CLK_PLLQ (8) //divide core clock by this to get 48MHz +// USB config +#define MICROPY_HW_USB_FS (1) + // UART config #define MICROPY_HW_UART1_TX (pin_A9) #define MICROPY_HW_UART1_RX (pin_A10) @@ -52,7 +50,7 @@ #define MICROPY_HW_SPI1_SCK (pin_A5) #define MICROPY_HW_SPI1_MISO (pin_A6) #define MICROPY_HW_SPI1_MOSI (pin_A7) -#if defined(USE_USB_HS_IN_FS) +#if MICROPY_HW_USB_HS_IN_FS // The HS USB uses B14 & B15 for D- and D+ #else #define MICROPY_HW_SPI2_NSS (pin_B12) diff --git a/ports/stm32/boards/STM32F439/mpconfigboard.mk b/ports/stm32/boards/STM32F439/mpconfigboard.mk index 0c30c06a3..ca97acbf6 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 d121b18c5..5b5a8a3e4 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 688a1ef62..66ef830bf 100644 --- a/ports/stm32/boards/STM32F4DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F4DISC/mpconfigboard.h @@ -3,16 +3,11 @@ #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) @@ -80,5 +75,6 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config +#define MICROPY_HW_USB_FS (1) #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F4DISC/mpconfigboard.mk index ece09caa1..b154dcfba 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/stm32f4xx_hal_conf.h b/ports/stm32/boards/STM32F4DISC/stm32f4xx_hal_conf.h index d3df51c10..daf9b63ce 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 50b9c1618..95201501b 100644 --- a/ports/stm32/boards/STM32F769DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F769DISC/mpconfigboard.h @@ -8,15 +8,10 @@ #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 @@ -74,5 +69,7 @@ #define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) // USB config (CN13 - USB OTG FS) +#define MICROPY_HW_USB_HS (1) +#define MICROPY_HW_USB_HS_IN_FS (1) /*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/ #define MICROPY_HW_USB_OTG_ID_PIN (pin_J12) diff --git a/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F769DISC/mpconfigboard.mk index 99234e4cf..873368ce5 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/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F769DISC/stm32f7xx_hal_conf.h index ce8254902..ff968bca9 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 4530a4706..dd268fb9c 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 41d49f64b..9fce1deeb 100644 --- a/ports/stm32/boards/STM32F7DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32F7DISC/mpconfigboard.h @@ -4,15 +4,10 @@ #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); @@ -75,6 +70,6 @@ void STM32F7DISC_board_early_init(void); // The Hardware VBUS detect only works on pin PA9. The STM32F7 Discovery uses // PA9 for VCP_TX functionality and connects the VBUS to pin J12 (so software // only detect). So we don't define the VBUS detect pin since that requires PA9. - +#define MICROPY_HW_USB_FS (1) /*#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_J12)*/ #define MICROPY_HW_USB_OTG_ID_PIN (pin_A10) diff --git a/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk b/ports/stm32/boards/STM32F7DISC/mpconfigboard.mk index 7c6bc4584..160218fd3 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/stm32f7xx_hal_conf.h b/ports/stm32/boards/STM32F7DISC/stm32f7xx_hal_conf.h index 3fbfb4310..ff968bca9 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 000000000..6b353a2f9 --- /dev/null +++ b/ports/stm32/boards/STM32L476DISC/bdev.c @@ -0,0 +1,21 @@ +#include "storage.h" + +// External SPI flash uses standard SPI interface + +const mp_soft_spi_obj_t soft_spi_bus = { + .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, + .polarity = 0, + .phase = 0, + .sck = MICROPY_HW_SPIFLASH_SCK, + .mosi = MICROPY_HW_SPIFLASH_MOSI, + .miso = MICROPY_HW_SPIFLASH_MISO, +}; + +const mp_spiflash_config_t spiflash_config = { + .bus_kind = MP_SPIFLASH_BUS_SPI, + .bus.u_spi.cs = MICROPY_HW_SPIFLASH_CS, + .bus.u_spi.data = (void*)&soft_spi_bus, + .bus.u_spi.proto = &mp_soft_spi_proto, +}; + +spi_bdev_t spi_bdev; diff --git a/ports/stm32/boards/STM32L476DISC/board_init.c b/ports/stm32/boards/STM32L476DISC/board_init.c index fdc41c401..eb44f320f 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 9dbadd530..3d8b74e4a 100644 --- a/ports/stm32/boards/STM32L476DISC/mpconfigboard.h +++ b/ports/stm32/boards/STM32L476DISC/mpconfigboard.h @@ -4,18 +4,13 @@ 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_CAN (1) +#define MICROPY_HW_ENABLE_USB (1) // use external SPI flash for storage #define MICROPY_HW_SPIFLASH_SIZE_BITS (128 * 1024 * 1024) @@ -24,6 +19,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) @@ -65,4 +71,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 72468d89c..2cad9e2e5 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 9348e0679..6bfb28118 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/common_basic.ld b/ports/stm32/boards/common_basic.ld new file mode 100644 index 000000000..2e428aa62 --- /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 000000000..52b2a677d --- /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 e5dea49d0..74b2ffb41 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 210c7b63c..c9f6516f1 100755 --- a/ports/stm32/boards/make-pins.py +++ b/ports/stm32/boards/make-pins.py @@ -207,18 +207,18 @@ class Pin(object): print("// ", end='') print('};') print('') - print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:s}, {:s}, {:d});'.format( + print('const pin_obj_t pin_{:s}_obj = PIN({:s}, {:d}, {:s}, {:s}, {:d});'.format( self.cpu_pin_name(), self.port_letter(), self.pin, self.alt_fn_name(null_if_0=True), self.adc_num_str(), self.adc_channel)) print('') def print_header(self, hdr_file): - hdr_file.write('extern const pin_obj_t pin_{:s};\n'. - format(self.cpu_pin_name())) + n = self.cpu_pin_name() + hdr_file.write('extern const pin_obj_t pin_{:s}_obj;\n'.format(n)) + hdr_file.write('#define pin_{:s} (&pin_{:s}_obj)\n'.format(n, n)) if self.alt_fn_count > 0: - hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. - format(self.cpu_pin_name())) + hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'.format(n)) def qstr_list(self): result = [] @@ -287,7 +287,7 @@ class Pins(object): for named_pin in named_pins: pin = named_pin.pin() if pin.is_board_pin(): - print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name())) + print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}_obj) }},'.format(named_pin.name(), pin.cpu_pin_name())) print('};') print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); @@ -305,13 +305,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_stm32f4.s b/ports/stm32/boards/startup_stm32f4.s new file mode 100644 index 000000000..e46a93b71 --- /dev/null +++ b/ports/stm32/boards/startup_stm32f4.s @@ -0,0 +1,522 @@ +/** + ****************************************************************************** + * @file startup_stm32.S + * @author MCD Application Team + * @version V2.0.0 + * @date 18-February-2014 + * @brief STM32Fxxxxx Devices vector table for Atollic TrueSTUDIO toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4/M7 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

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

© COPYRIGHT 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system initialization function.*/ + bl SystemInit +/* Call static constructors */ + /*bl __libc_init_array*/ +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M4/M7. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_PVM_IRQHandler /* PVD and PVM through EXTI line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */ + .word DMA1_Channel2_IRQHandler /* DMA1 Channel 2 */ + .word DMA1_Channel3_IRQHandler /* DMA1 Channel 3 */ + .word DMA1_Channel4_IRQHandler /* DMA1 Channel 4 */ + .word DMA1_Channel5_IRQHandler /* DMA1 Channel 5 */ + .word DMA1_Channel6_IRQHandler /* DMA1 Channel 6 */ + .word DMA1_Channel7_IRQHandler /* DMA1 Channel 7 */ + .word ADC1_2_IRQHandler /* ADC1 and ADC2 */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM15_IRQHandler /* TIM1 Break and TIM15 */ + .word TIM1_UP_TIM16_IRQHandler /* TIM1 Update and TIM16 */ + .word TIM1_TRG_COM_TIM17_IRQHandler /* TIM1 Trigger and Commutation and TIM17 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word DFSDM3_IRQHandler /* Digital filter for sigma delta modulator 3 */ + .word TIM8_BRK_IRQHandler /* TIM8 Break */ + .word TIM8_UP_IRQHandler /* TIM8 Update */ + .word TIM8_TRG_COM_IRQHandler /* TIM8 Trigger and Commutation */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word ADC3_IRQHandler /* ADC3 global interrupt */ + .word FMC_IRQHandler /* FMC */ + .word SDMMC1_IRQHandler /* SDMMC1 */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Channel1_IRQHandler /* DMA2 Channel 1 */ + .word DMA2_Channel2_IRQHandler /* DMA2 Channel 2 */ + .word DMA2_Channel3_IRQHandler /* DMA2 Channel 3 */ + .word DMA2_Channel4_IRQHandler /* DMA2 Channel 4 */ + .word DMA2_Channel5_IRQHandler /* DMA2 Channel 5 */ + .word DFSDM0_IRQHandler /* Digital filter for sigma delta modulator 0 */ + .word DFSDM1_IRQHandler /* Digital filter for sigma delta modulator 1 */ + .word DFSDM2_IRQHandler /* Digital filter for sigma delta modulator 2 */ + .word COMP_IRQHandler /* Comporator thru EXTI line */ + .word LPTIM1_IRQHandler /* Low power timer 1 */ + .word LPTIM2_IRQHandler /* Low power timer 2 */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Channel6_IRQHandler /* DMA2 Channel 6 */ + .word DMA2_Channel7_IRQHandler /* DMA2 Channel 7 */ + .word LPUART1_IRQHandler /* Low power UART */ + .word QUADSPI_IRQHandler /* Quad SPI */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word SAI1_IRQHandler /* Serial audio interface 1 */ + .word SAI2_IRQHandler /* Serial audio interface 2 */ + .word SWPMI1_IRQHandler /* Single wire protocole 1 */ + .word TSC_IRQHandler /* Touch sensig controller */ + .word LCD_IRQHandler /* LCD */ + .word 0 /* CRYP crypto */ + .word RNG_IRQHandler /* Random number generator */ + .word FPU_IRQHandler /* FPU */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_PVM_IRQHandler + .thumb_set PVD_PVM_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + + .weak ADC1_2_IRQHandler + .thumb_set ADC1_2_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM15_IRQHandler + .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM16_IRQHandler + .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM17_IRQHandler + .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak DFSDM3_IRQHandler + .thumb_set DFSDM3_IRQHandler,Default_Handler + + .weak TIM8_BRK_IRQHandler + .thumb_set TIM8_BRK_IRQHandler,Default_Handler + + .weak TIM8_UP_IRQHandler + .thumb_set TIM8_UP_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_IRQHandler + .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak ADC3_IRQHandler + .thumb_set ADC3_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Channel1_IRQHandler + .thumb_set DMA2_Channel1_IRQHandler,Default_Handler + + .weak DMA2_Channel2_IRQHandler + .thumb_set DMA2_Channel2_IRQHandler,Default_Handler + + .weak DMA2_Channel3_IRQHandler + .thumb_set DMA2_Channel3_IRQHandler,Default_Handler + + .weak DMA2_Channel4_IRQHandler + .thumb_set DMA2_Channel4_IRQHandler,Default_Handler + + .weak DMA2_Channel5_IRQHandler + .thumb_set DMA2_Channel5_IRQHandler,Default_Handler + + .weak DFSDM0_IRQHandler + .thumb_set DFSDM0_IRQHandler,Default_Handler + + .weak DFSDM1_IRQHandler + .thumb_set DFSDM1_IRQHandler,Default_Handler + + .weak DFSDM2_IRQHandler + .thumb_set DFSDM2_IRQHandler,Default_Handler + + .weak COMP_IRQHandler + .thumb_set COMP_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Channel6_IRQHandler + .thumb_set DMA2_Channel6_IRQHandler,Default_Handler + + .weak DMA2_Channel7_IRQHandler + .thumb_set DMA2_Channel7_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak QUADSPI_IRQHandler + .thumb_set QUADSPI_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak SAI2_IRQHandler + .thumb_set SAI2_IRQHandler,Default_Handler + + .weak SWPMI1_IRQHandler + .thumb_set SWPMI1_IRQHandler,Default_Handler + + .weak TSC_IRQHandler + .thumb_set TSC_IRQHandler,Default_Handler + + .weak LCD_IRQHandler + .thumb_set LCD_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32/boards/stm32f401xd.ld b/ports/stm32/boards/stm32f401xd.ld index 89f605609..7c0e79018 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 ae2f89904..e76bbad1c 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 c6107913f..0375491f6 100644 --- a/ports/stm32/boards/stm32f405.ld +++ b/ports/stm32/boards/stm32f405.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f411.ld b/ports/stm32/boards/stm32f411.ld index 7adfa35c9..9e3e6bc15 100644 --- a/ports/stm32/boards/stm32f411.ld +++ b/ports/stm32/boards/stm32f411.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f429.ld b/ports/stm32/boards/stm32f429.ld index a0931684d..d80f7f541 100644 --- a/ports/stm32/boards/stm32f429.ld +++ b/ports/stm32/boards/stm32f429.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld index a76a0ebc7..16c606ecc 100644 --- a/ports/stm32/boards/stm32f439.ld +++ b/ports/stm32/boards/stm32f439.ld @@ -21,9 +21,6 @@ _minimum_heap_size = 16K; /* top end of the stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f746.ld b/ports/stm32/boards/stm32f746.ld index ce5e85bb6..b5864453d 100644 --- a/ports/stm32/boards/stm32f746.ld +++ b/ports/stm32/boards/stm32f746.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld index 225abd810..c05fd8021 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 ab2e248bb..0c8069ec2 100644 --- a/ports/stm32/boards/stm32f767_af.csv +++ b/ports/stm32/boards/stm32f767_af.csv @@ -1,170 +1,170 @@ -Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15 -,,SYS,I2C4/UART5/TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/DFSDM1/CEC,I2C1/2/3/4/USART1/CEC,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5/6,SPI2/I2S2/SPI3/I2S3/SAI1/I2C4/UART4/DFSDM1,SPI2/I2S2/SPI3/I2S3/SPI6/USART1/2/3/UART5/DFSDM1/SPDIF,SPI6/SAI2/USART6/UART4/5/7/8/OTG_FS/SPDIF,CAN1/2/TIM12/13/14/QUADSPI/FMC/LCD,SAI2/QUADSPI/SDMMC2/DFSDM1/OTG2_HS/OTG1_FS/LCD,I2C4/CAN3/SDMMC2/ETH,UART7/FMC/SDMMC1/MDIOS/OTG2_FS,DCMI/LCD/DSI,LCD,SYS -PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT -PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT -PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT -PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT -PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT -PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT -PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,SPI6_MISO,TIM13_CH1,,,MDIOS_MDC,DCMI_PIXCLK,LCD_G2,EVENTOUT -PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT -PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,CAN3_RX,UART7_RX,LCD_B3,LCD_R6,EVENTOUT -PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,LCD_R5,EVENTOUT -PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,LCD_B4,OTG_FS_ID,,MDIOS_MDIO,DCMI_D1,LCD_B1,EVENTOUT -PortA,PA11,,TIM1_CH4,,,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT -PortA,PA12,,TIM1_ETR,,,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT -PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT -PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT -PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,CAN3_TX,UART7_TX,,,EVENTOUT -PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM1_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT -PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATAIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT -PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,DFSDM1_CKIN1,,,,,EVENTOUT -PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,,SDMMC2_D2,CAN3_RX,UART7_RX,,,EVENTOUT -PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,SPI6_MISO,,SDMMC2_D3,CAN3_TX,UART7_TX,,,EVENTOUT -PortB,PB5,,UART5_RX,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT -PortB,PB6,,UART5_TX,TIM4_CH1,HDMI_CEC,I2C1_SCL,,DFSDM1_DATAIN5,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,I2C4_SCL,FMC_SDNE1,DCMI_D5,,EVENTOUT -PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,DFSDM1_CKIN5,USART1_RX,,,,I2C4_SDA,FMC_NL,DCMI_VSYNC,,EVENTOUT -PortB,PB8,,I2C4_SCL,TIM4_CH3,TIM10_CH1,I2C1_SCL,,DFSDM1_CKIN7,UART5_RX,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT -PortB,PB9,,I2C4_SDA,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN7,UART5_TX,,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT -PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT -PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DSI_TE,LCD_G5,EVENTOUT -PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN1,USART3_CK,UART5_RX,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT -PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,DFSDM1_CKIN1,USART3_CTS,UART5_TX,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT -PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,USART1_TX,SPI2_MISO,DFSDM1_DATAIN2,USART3_RTS,UART4_RTS,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT -PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SD,DFSDM1_CKIN2,,UART4_CTS,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT -PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATAIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT -PortC,PC1,TRACED0,,,DFSDM1_DATAIN0,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,DFSDM1_CKIN4,ETH_MDC,MDIOS_MDC,,,EVENTOUT -PortC,PC2,,,,DFSDM1_CKIN1,,SPI2_MISO,DFSDM1_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT -PortC,PC3,,,,DFSDM1_DATAIN1,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT -PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT -PortC,PC5,,,,DFSDM1_DATAIN2,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT -PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,DFSDM1_CKIN3,USART6_TX,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT -PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,DFSDM1_DATAIN3,USART6_RX,FMC_NE1,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT -PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,FMC_NE2/FMC_NCE,,,SDMMC1_D0,DCMI_D2,,EVENTOUT -PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,LCD_G3,,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT -PortC,PC10,,,,DFSDM1_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT -PortC,PC11,,,,DFSDM1_DATAIN5,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT -PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT -PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT -PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT -PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT -PortD,PD0,,,,DFSDM1_CKIN6,,,DFSDM1_DATAIN7,,UART4_RX,CAN1_RX,,,FMC_D2,,,EVENTOUT -PortD,PD1,,,,DFSDM1_DATAIN6,,,DFSDM1_CKIN7,,UART4_TX,CAN1_TX,,,FMC_D3,,,EVENTOUT -PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT -PortD,PD3,,,,DFSDM1_CKOUT,,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN0,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT -PortD,PD4,,,,,,,DFSDM1_CKIN0,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT -PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT -PortD,PD6,,,,DFSDM1_CKIN4,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,DFSDM1_DATAIN1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT -PortD,PD7,,,,DFSDM1_DATAIN4,,SPI1_MOSI/I2S1_SD,DFSDM1_CKIN1,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT -PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT -PortD,PD9,,,,DFSDM1_DATAIN3,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT -PortD,PD10,,,,DFSDM1_CKOUT,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT -PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT -PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT -PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT -PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT -PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT -PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT -PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT -PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT -PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT -PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,DFSDM1_DATAIN3,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT -PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,DFSDM1_CKIN3,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT -PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT -PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATAIN2,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT -PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT -PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT -PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATAIN4,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT -PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,DFSDM1_CKIN4,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT -PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,DFSDM1_DATAIN5,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT -PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,DFSDM1_CKIN5,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT -PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT -PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT -PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT -PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT -PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT -PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT -PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT -PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT -PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT -PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT -PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT -PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT -PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT -PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT -PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT -PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATAIN6,,,,,,FMC_A7,,,EVENTOUT -PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,,,,FMC_A8,,,EVENTOUT -PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT -PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT -PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT -PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT -PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT -PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT -PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT -PortG,PG6,,,,,,,,,,,,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT -PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT -PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT -PortG,PG9,,,,,,SPI1_MISO,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT -PortG,PG10,,,,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT -PortG,PG11,,,,,,SPI1_SCK/I2S1_CK,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT -PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT -PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT -PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT -PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT -PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT -PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT -PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT -PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT -PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT -PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT -PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT -PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT -PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT -PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT -PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT -PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT -PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT -PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT -PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT -PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT -PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT -PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT -PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT -PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT -PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT -PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT -PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT -PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT -PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT -PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT -PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT -PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT -PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT -PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT -PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT -PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT -PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT -PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT -PortJ,PJ2,,,,,,,,,,,,,,DSI_TE,LCD_R3,EVENTOUT -PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT -PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT -PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT -PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT -PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT -PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT -PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT -PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT -PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT -PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT -PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT -PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT -PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT -PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT -PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT -PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT -PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT -PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT -PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT -PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT -PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,I2C4/UART5/TIM1/2,TIM3/4/5,TIM8/9/10/11/LPTIM1/DFSDM1/CEC,I2C1/2/3/4/USART1/CEC,SPI1/I2S1/SPI2/I2S2/SPI3/I2S3/SPI4/5/6,SPI2/I2S2/SPI3/I2S3/SAI1/I2C4/UART4/DFSDM1,SPI2/I2S2/SPI3/I2S3/SPI6/USART1/2/3/UART5/DFSDM1/SPDIF,SPI6/SAI2/USART6/UART4/5/7/8/OTG_FS/SPDIF,CAN1/2/TIM12/13/14/QUADSPI/FMC/LCD,SAI2/QUADSPI/SDMMC2/DFSDM1/OTG2_HS/OTG1_FS/LCD,I2C4/CAN3/SDMMC2/ETH,UART7/FMC/SDMMC1/MDIOS/OTG2_FS,DCMI/LCD/DSI,LCD,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT,ADC123_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT,ADC123_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT,ADC123_IN3 +PortA,PA4,,,,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT,ADC12_IN4 +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT,ADC12_IN5 +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,SPI6_MISO,TIM13_CH1,,,MDIOS_MDC,DCMI_PIXCLK,LCD_G2,EVENTOUT,ADC12_IN6 +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SD,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT,ADC12_IN7 +PortA,PA8,MCO1,TIM1_CH1,,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,CAN3_RX,UART7_RX,LCD_B3,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,,,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,,,,,DCMI_D0,LCD_R5,EVENTOUT, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,LCD_B4,OTG_FS_ID,,MDIOS_MDIO,DCMI_D1,LCD_B1,EVENTOUT, +PortA,PA11,,TIM1_CH4,,,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,,,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,CAN3_TX,UART7_TX,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM1_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT,ADC12_IN8 +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM1_DATAIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT,ADC12_IN9 +PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,DFSDM1_CKIN1,,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,,SDMMC2_D2,CAN3_RX,UART7_RX,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,SPI6_MISO,,SDMMC2_D3,CAN3_TX,UART7_TX,,,EVENTOUT, +PortB,PB5,,UART5_RX,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI/I2S1_SD,SPI3_MOSI/I2S3_SD,,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,LCD_G7,EVENTOUT, +PortB,PB6,,UART5_TX,TIM4_CH1,HDMI_CEC,I2C1_SCL,,DFSDM1_DATAIN5,USART1_TX,,CAN2_TX,QUADSPI_BK1_NCS,I2C4_SCL,FMC_SDNE1,DCMI_D5,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,DFSDM1_CKIN5,USART1_RX,,,,I2C4_SDA,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,I2C4_SCL,TIM4_CH3,TIM10_CH1,I2C1_SCL,,DFSDM1_CKIN7,UART5_RX,,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,I2C4_SDA,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN7,UART5_TX,,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM1_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DSI_TE,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM1_DATAIN1,USART3_CK,UART5_RX,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,DFSDM1_CKIN1,USART3_CTS,UART5_TX,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,USART1_TX,SPI2_MISO,DFSDM1_DATAIN2,USART3_RTS,UART4_RTS,TIM12_CH1,SDMMC2_D0,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SD,DFSDM1_CKIN2,,UART4_CTS,TIM12_CH2,SDMMC2_D1,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,DFSDM1_CKIN0,,,DFSDM1_DATAIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT,ADC123_IN10 +PortC,PC1,TRACED0,,,DFSDM1_DATAIN0,,SPI2_MOSI/I2S2_SD,SAI1_SD_A,,,,DFSDM1_CKIN4,ETH_MDC,MDIOS_MDC,,,EVENTOUT,ADC123_IN11 +PortC,PC2,,,,DFSDM1_CKIN1,,SPI2_MISO,DFSDM1_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT,ADC123_IN12 +PortC,PC3,,,,DFSDM1_DATAIN1,,SPI2_MOSI/I2S2_SD,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT,ADC123_IN13 +PortC,PC4,,,,DFSDM1_CKIN2,,I2S1_MCK,,,SPDIFRX_IN2,,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT,ADC12_IN14 +PortC,PC5,,,,DFSDM1_DATAIN2,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT,ADC12_IN15 +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,DFSDM1_CKIN3,USART6_TX,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,DFSDM1_DATAIN3,USART6_RX,FMC_NE1,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,FMC_NE2/FMC_NCE,,,SDMMC1_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,LCD_G3,,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT, +PortC,PC10,,,,DFSDM1_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,,DFSDM1_DATAIN5,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,DFSDM1_CKIN6,,,DFSDM1_DATAIN7,,UART4_RX,CAN1_RX,,,FMC_D2,,,EVENTOUT, +PortD,PD1,,,,DFSDM1_DATAIN6,,,DFSDM1_CKIN7,,UART4_TX,CAN1_TX,,,FMC_D3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,DFSDM1_CKOUT,,SPI2_SCK/I2S2_CK,DFSDM1_DATAIN0,USART2_CTS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,,,,,DFSDM1_CKIN0,USART2_RTS,,,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,,DFSDM1_CKIN4,,SPI3_MOSI/I2S3_SD,SAI1_SD_A,USART2_RX,,,DFSDM1_DATAIN1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,DFSDM1_DATAIN4,,SPI1_MOSI/I2S1_SD,DFSDM1_CKIN1,USART2_CK,SPDIFRX_IN0,,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,DFSDM1_CKIN3,,,,USART3_TX,SPDIFRX_IN1,,,,FMC_D13,,,EVENTOUT, +PortD,PD9,,,,DFSDM1_DATAIN3,,,,USART3_RX,,,,,FMC_D14,,,EVENTOUT, +PortD,PD10,,,,DFSDM1_CKOUT,,,,USART3_CK,,,,,FMC_D15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,,I2C4_SMBA,,,USART3_CTS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16/FMC_CLE,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,LPTIM1_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17/FMC_ALE,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,LPTIM1_OUT,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,UART8_CTS,,,,FMC_D0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,UART8_RTS,,,,FMC_D1,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,LPTIM1_ETR,,,,,UART8_RX,,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,,,LPTIM1_IN2,,,,,UART8_TX,,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,,,,SPI4_SCK,SAI1_MCLK_A,,,QUADSPI_BK1_IO2,,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,,,SAI1_SD_B,,,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,,,,SPI4_NSS,SAI1_FS_A,,,,DFSDM1_DATAIN3,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,SPI4_MISO,SAI1_SCK_A,,,,DFSDM1_CKIN3,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,,TIM9_CH2,,SPI4_MOSI,SAI1_SD_A,,,,SAI2_MCK_B,,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,,,,DFSDM1_DATAIN2,,UART7_RX,,QUADSPI_BK2_IO0,,FMC_D4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM1_CKIN2,,UART7_TX,,QUADSPI_BK2_IO1,,FMC_D5,,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,,,,DFSDM1_CKOUT,,UART7_RTS,,QUADSPI_BK2_IO2,,FMC_D6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,,,,DFSDM1_DATAIN4,,UART7_CTS,,QUADSPI_BK2_IO3,,FMC_D7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,,,SPI4_NSS,DFSDM1_CKIN4,,,,SAI2_SD_B,,FMC_D8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,,,SPI4_SCK,DFSDM1_DATAIN5,,,,SAI2_SCK_B,,FMC_D9,,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,,,SPI4_MISO,DFSDM1_CKIN5,,,,SAI2_FS_B,,FMC_D10,,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,,,,,,,,FMC_D12,,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN9 +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN14 +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN15 +PortF,PF6,,,,TIM10_CH1,,SPI5_NSS,SAI1_SD_B,,UART7_RX,QUADSPI_BK1_IO3,,,,,,EVENTOUT,ADC3_IN4 +PortF,PF7,,,,TIM11_CH1,,SPI5_SCK,SAI1_MCLK_B,,UART7_TX,QUADSPI_BK1_IO2,,,,,,EVENTOUT,ADC3_IN5 +PortF,PF8,,,,,,SPI5_MISO,SAI1_SCK_B,,UART7_RTS,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT,ADC3_IN6 +PortF,PF9,,,,,,SPI5_MOSI,SAI1_FS_B,,UART7_CTS,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT,ADC3_IN7 +PortF,PF10,,,,,,,,,,QUADSPI_CLK,,,,DCMI_D11,LCD_DE,EVENTOUT,ADC3_IN8 +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,,I2C4_SMBA,,DFSDM1_DATAIN6,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,,I2C4_SCL,,DFSDM1_CKIN6,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,FMC_A13,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,,,,,SAI1_MCLK_A,,USART6_CK,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,,,SPI6_NSS,,SPDIFRX_IN2,USART6_RTS,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT, +PortG,PG9,,,,,,SPI1_MISO,,SPDIFRX_IN3,USART6_RX,QUADSPI_BK2_IO2,SAI2_FS_B,SDMMC2_D0,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,SDMMC2_D1,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,,,,SPI1_SCK/I2S1_CK,,SPDIFRX_IN0,,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,,,LPTIM1_IN1,,SPI6_MISO,,SPDIFRX_IN1,USART6_RTS,LCD_B4,,SDMMC2_D3,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,TRACED0,,,LPTIM1_OUT,,SPI6_SCK,,,USART6_CTS,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG14,TRACED1,,,LPTIM1_ETR,,SPI6_MOSI,,,USART6_TX,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT, +PortG,PG15,,,,,,,,,USART6_CTS,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,,,LPTIM1_IN2,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,,,I2C2_SMBA,SPI5_SCK,,,,TIM12_CH1,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT, +PortH,PH8,,,,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,,,I2C3_SMBA,,,,,TIM12_CH2,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,DSI_TE,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,,,,,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,,,,,,,,,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,,,,,,,,,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,,,,,,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,,,,,,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,LCD_G4,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,,,,,,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,,,,,,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,,,,,,,,,,,,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, diff --git a/ports/stm32/boards/stm32f769.ld b/ports/stm32/boards/stm32f769.ld index c4cabe7a4..d6da43943 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 000000000..77bbfacb1 --- /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 000000000..24710d717 --- /dev/null +++ b/ports/stm32/boards/stm32h743_af.csv @@ -0,0 +1,170 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS,TIM1/2/16/17/LPTIM1/HRTIM1,SAI1/TIM3/4/5/12/HRTIM1,LPUART/TIM8/LPTIM2/3/4/5/HRTIM1/DFSDM,I2C1/2/3/4/USART1/TIM15/LPTIM2/DFSDM/CEC,SPI1/2/3/4/5/6/CEC,SPI2/3/SAI1/3/I2C4/UART4/DFSDM,SPI2/3/6/USART1/2/3/6/UART7/SDMMC1,SPI6/SAI2/4/UART4/5/8/LPUART/SDMMC1/SPDIFRX,SAI4/FDCAN1/2/TIM13/14/QUADSPI/FMC/SDMMC2/LCD/SPDIFRX,SAI2/4/TIM8/QUADSPI/SDMMC2/OTG1_HS/OTG2_FS/LCD,I2C4/UART7/SWPMI1/TIM1/8/DFSDM/SDMMC2/MDIOS/ETH,TIM1/8/FMC/SDMMC1/MDIOS/OTG1_FS/LCD,TIM1/DCMI/LCD/COMP,UART5/LCD,SYS,ADC +PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,TIM15_BKIN,,,USART2_CTS_NSS,UART4_TX,SDMMC2_CMD,SAI2_SD_B,ETH_MII_CRS,,,,EVENTOUT, +PortA,PA1,,TIM2_CH2,TIM5_CH2,LPTIM3_OUT,TIM15_CH1N,,,USART2_RTS,UART4_RX,QUADSPI_BK1_IO3,SAI2_MCK_B,ETH_MII_RX_CLK/ETH_RMII_REF_CLK,,,LCD_R2,EVENTOUT, +PortA,PA2,,TIM2_CH3,TIM5_CH3,LPTIM4_OUT,TIM15_CH1,,,USART2_TX,SAI2_SCK_B,,,ETH_MDIO,MDIOS_MDIO,,LCD_R1,EVENTOUT, +PortA,PA3,,TIM2_CH4,TIM5_CH4,LPTIM5_OUT,TIM15_CH2,,,USART2_RX,,LCD_B2,OTG_HS_ULPI_D0,ETH_MII_COL,,,LCD_B5,EVENTOUT, +PortA,PA4,,,TIM5_ETR,,,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,USART2_CK,SPI6_NSS,,,,OTG_HS_SOF,DCMI_HSYNC,LCD_VSYNC,EVENTOUT, +PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK/I2S1_CK,,,SPI6_SCK,,OTG_HS_ULPI_CK,,,,LCD_R4,EVENTOUT, +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO/I2S1_SDI,,,SPI6_MISO,TIM13_CH1,TIM8_BKIN_COMP12,MDIOS_MDC,TIM1_BKIN_COMP12,DCMI_PIXCLK,LCD_G2,EVENTOUT, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI/I2S1_SDO,,,SPI6_MOSI,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,FMC_SDNWE,,,EVENTOUT, +PortA,PA8,MCO1,TIM1_CH1,HRTIM_CHB2,TIM8_BKIN2,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,UART7_RX,TIM8_BKIN2_COMP12,LCD_B3,LCD_R6,EVENTOUT, +PortA,PA9,,TIM1_CH2,HRTIM_CHC1,LPUART1_TX,I2C3_SMBA,SPI2_SCK/I2S2_CK,,USART1_TX,,CAN1_RXFD,,ETH_TX_ER,,DCMI_D0,LCD_R5,EVENTOUT, +PortA,PA10,,TIM1_CH3,HRTIM_CHC2,LPUART1_RX,,,,USART1_RX,,CAN1_TXFD,OTG_FS_ID,MDIOS_MDIO,LCD_B4,DCMI_D1,LCD_B1,EVENTOUT, +PortA,PA11,,TIM1_CH4,HRTIM_CHD1,LPUART1_CTS,,SPI2_NSS/I2S2_WS,UART4_RX,USART1_CTS_NSS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT, +PortA,PA12,,TIM1_ETR,HRTIM_CHD2,LPUART1_RTS,,SPI2_SCK/I2S2_CK,UART4_TX,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,HRTIM_FLT1,,HDMI_CEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,SPI6_NSS,UART4_RTS,,,UART7_TX,,,,EVENTOUT, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,DFSDM_CKOUT,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,LCD_G1,EVENTOUT, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN1,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,LCD_G0,EVENTOUT, +PortB,PB2,,,SAI1_D1,,DFSDM_CKIN1,,SAI1_SD_A,SPI3_MOSI/I2S3_SDO,SAI4_SD_A,QUADSPI_CLK,SAI4_D1,ETH_TX_ER,,,,EVENTOUT, +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,HRTIM_FLT4,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,SPI6_SCK,SDMMC2_D2,,UART7_RX,,,,EVENTOUT, +PortB,PB4,NJTRST,TIM16_BKIN,TIM3_CH1,HRTIM_EEV6,,SPI1_MISO/I2S1_SDI,SPI3_MISO/I2S3_SDI,SPI2_NSS/I2S2_WS,SPI6_MISO,SDMMC2_D3,,UART7_TX,,,,EVENTOUT, +PortB,PB5,,TIM17_BKIN,TIM3_CH2,HRTIM_EEV7,I2C1_SMBA,SPI1_MOSI/I2S1_SDO,I2C4_SMBA,SPI3_MOSI/I2S3_SDO,SPI6_MOSI,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,FMC_SDCKE1,DCMI_D10,UART5_RX,EVENTOUT, +PortB,PB6,,TIM16_CH1N,TIM4_CH1,HRTIM_EEV8,I2C1_SCL,HDMI_CEC,I2C4_SCL,USART1_TX,LPUART1_TX,CAN2_TX,QUADSPI_BK1_NCS,DFSDM_DATIN5,FMC_SDNE1,DCMI_D5,UART5_TX,EVENTOUT, +PortB,PB7,,TIM17_CH1N,TIM4_CH2,HRTIM_EEV9,I2C1_SDA,,I2C4_SDA,USART1_RX,LPUART1_RX,CAN2_TXFD,,DFSDM_CKIN5,FMC_NL,DCMI_VSYNC,,EVENTOUT, +PortB,PB8,,TIM16_CH1,TIM4_CH3,DFSDM_CKIN7,I2C1_SCL,,I2C4_SCL,SDMMC1_CKIN,UART4_RX,CAN1_RX,SDMMC2_D4,ETH_MII_TXD3,SDMMC1_D4,DCMI_D6,LCD_B6,EVENTOUT, +PortB,PB9,,TIM17_CH1,TIM4_CH4,DFSDM_DATIN7,I2C1_SDA,SPI2_NSS/I2S2_WS,I2C4_SDA,SDMMC1_CDIR,UART4_TX,CAN1_TX,SDMMC2_D5,I2C4_SMBA,SDMMC1_D5,DCMI_D7,LCD_B7,EVENTOUT, +PortB,PB10,,TIM2_CH3,HRTIM_SCOUT,LPTIM2_IN1,I2C2_SCL,SPI2_SCK/I2S2_CK,DFSDM_DATIN7,USART3_TX,,QUADSPI_BK1_NCS,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,LCD_G4,EVENTOUT, +PortB,PB11,,TIM2_CH4,HRTIM_SCIN,LPTIM2_ETR,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,LCD_G5,EVENTOUT, +PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,DFSDM_DATIN1,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,TIM1_BKIN_COMP12,UART5_RX,EVENTOUT, +PortB,PB13,,TIM1_CH1N,,LPTIM2_OUT,,SPI2_SCK/I2S2_CK,DFSDM_CKIN1,USART3_CTS_NSS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,UART5_TX,EVENTOUT, +PortB,PB14,,TIM1_CH2N,TIM12_CH1,TIM8_CH2N,USART1_TX,SPI2_MISO/I2S2_SDI,DFSDM_DATIN2,USART3_RTS,UART4_RTS,SDMMC2_D0,,,OTG_HS_DM,,,EVENTOUT, +PortB,PB15,RTC_REFIN,TIM1_CH3N,TIM12_CH2,TIM8_CH3N,USART1_RX,SPI2_MOSI/I2S2_SDO,DFSDM_CKIN2,,UART4_CTS,SDMMC2_D1,,,OTG_HS_DP,,,EVENTOUT, +PortC,PC0,,,,DFSDM_CKIN0,,,DFSDM_DATIN4,,SAI2_FS_B,,OTG_HS_ULPI_STP,,FMC_SDNWE,,LCD_R5,EVENTOUT, +PortC,PC1,TRACED0,,SAI1_D1,DFSDM_DATIN0,DFSDM_CKIN4,SPI2_MOSI/I2S2_SDO,SAI1_SD_A,,SAI4_SD_A,SDMMC2_CK,SAI4_D1,ETH_MDC,MDIOS_MDC,,,EVENTOUT, +PortC,PC2,,,,DFSDM_CKIN1,,SPI2_MISO/I2S2_SDI,DFSDM_CKOUT,,,,OTG_HS_ULPI_DIR,ETH_MII_TXD2,FMC_SDNE0,,,EVENTOUT, +PortC,PC3,,,,DFSDM_DATIN1,,SPI2_MOSI/I2S2_SDO,,,,,OTG_HS_ULPI_NXT,ETH_MII_TX_CLK,FMC_SDCKE0,,,EVENTOUT, +PortC,PC4,,,,DFSDM_CKIN2,,I2S1_MCK,,,,SPDIFRX_IN2,,ETH_MII_RXD0/ETH_RMII_RXD0,FMC_SDNE0,,,EVENTOUT, +PortC,PC5,,,SAI1_D3,DFSDM_DATIN2,,,,,,SPDIFRX_IN3,SAI4_D3,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,COMP_1_OUT,,EVENTOUT, +PortC,PC6,,HRTIM_CHA1,TIM3_CH1,TIM8_CH1,DFSDM_CKIN3,I2S2_MCK,,USART6_TX,SDMMC1_D0DIR,FMC_NWAIT,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT, +PortC,PC7,TRGIO,HRTIM_CHA2,TIM3_CH2,TIM8_CH2,DFSDM_DATIN3,,I2S3_MCK,USART6_RX,SDMMC1_D123DIR,FMC_NE1,SDMMC2_D7,SWPMI_TX,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT, +PortC,PC8,TRACED1,HRTIM_CHB1,TIM3_CH3,TIM8_CH3,,,,USART6_CK,UART5_RTS,FMC_NE2/FMC_NCE,,SWPMI_RX,SDMMC1_D0,DCMI_D2,,EVENTOUT, +PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,,UART5_CTS,QUADSPI_BK1_IO0,LCD_G3,SWPMI_SUSPEND,SDMMC1_D1,DCMI_D3,LCD_B2,EVENTOUT, +PortC,PC10,,,HRTIM_EEV1,DFSDM_CKIN5,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT, +PortC,PC11,,,HRTIM_FLT2,DFSDM_DATIN5,,,SPI3_MISO/I2S3_SDI,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT, +PortC,PC12,TRACED3,,HRTIM_EEV2,,,,SPI3_MOSI/I2S3_SDO,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,DFSDM_CKIN6,,,SAI3_SCK_A,,UART4_RX,CAN1_RX,,,FMC_D2/FMC_DA2,,,EVENTOUT, +PortD,PD1,,,,DFSDM_DATIN6,,,SAI3_SD_A,,UART4_TX,CAN1_TX,,,FMC_D3/FMC_DA3,,,EVENTOUT, +PortD,PD2,TRACED2,,TIM3_ETR,,,,,,UART5_RX,,,,SDMMC1_CMD,DCMI_D11,,EVENTOUT, +PortD,PD3,,,,DFSDM_CKOUT,,SPI2_SCK/I2S2_CK,,USART2_CTS_NSS,,,,,FMC_CLK,DCMI_D5,LCD_G7,EVENTOUT, +PortD,PD4,,,HRTIM_FLT3,,,,SAI3_FS_A,USART2_RTS,,CAN1_RXFD,,,FMC_NOE,,,EVENTOUT, +PortD,PD5,,,HRTIM_EEV3,,,,,USART2_TX,,CAN1_TXFD,,,FMC_NWE,,,EVENTOUT, +PortD,PD6,,,SAI1_D1,DFSDM_CKIN4,DFSDM_DATIN1,SPI3_MOSI/I2S3_SDO,SAI1_SD_A,USART2_RX,SAI4_SD_A,CAN2_RXFD,SAI4_D1,SDMMC2_CK,FMC_NWAIT,DCMI_D10,LCD_B2,EVENTOUT, +PortD,PD7,,,,DFSDM_DATIN4,,SPI1_MOSI/I2S1_SDO,DFSDM_CKIN1,USART2_CK,,SPDIFRX_IN0,,SDMMC2_CMD,FMC_NE1,,,EVENTOUT, +PortD,PD8,,,,DFSDM_CKIN3,,,SAI3_SCK_B,USART3_TX,,SPDIFRX_IN1,,,FMC_D13/FMC_DA13,,,EVENTOUT, +PortD,PD9,,,,DFSDM_DATIN3,,,SAI3_SD_B,USART3_RX,,CAN2_RXFD,,,FMC_D14/FMC_DA14,,,EVENTOUT, +PortD,PD10,,,,DFSDM_CKOUT,,,SAI3_FS_B,USART3_CK,,CAN2_TXFD,,,FMC_D15/FMC_DA15,,LCD_B3,EVENTOUT, +PortD,PD11,,,,LPTIM2_IN2,I2C4_SMBA,,,USART3_CTS_NSS,,QUADSPI_BK1_IO0,SAI2_SD_A,,FMC_A16,,,EVENTOUT, +PortD,PD12,,LPTIM1_IN1,TIM4_CH1,LPTIM2_IN1,I2C4_SCL,,,USART3_RTS,,QUADSPI_BK1_IO1,SAI2_FS_A,,FMC_A17,,,EVENTOUT, +PortD,PD13,,LPTIM1_OUT,TIM4_CH2,,I2C4_SDA,,,,,QUADSPI_BK1_IO3,SAI2_SCK_A,,FMC_A18,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,SAI3_MCLK_B,,UART8_CTS,,,,FMC_D0/FMC_DA0,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,SAI3_MCLK_A,,UART8_RTS,,,,FMC_D1/FMC_DA1,,,EVENTOUT, +PortE,PE0,,LPTIM1_ETR,TIM4_ETR,HRTIM_SCIN,LPTIM2_ETR,,,,UART8_RX,CAN1_RXFD,SAI2_MCK_A,,FMC_NBL0,DCMI_D2,,EVENTOUT, +PortE,PE1,,LPTIM1_IN2,,HRTIM_SCOUT,,,,,UART8_TX,CAN1_TXFD,,,FMC_NBL1,DCMI_D3,,EVENTOUT, +PortE,PE2,TRACECLK,,SAI1_CK1,,,SPI4_SCK,SAI1_MCLK_A,,SAI4_MCLK_A,QUADSPI_BK1_IO2,SAI4_CK1,ETH_MII_TXD3,FMC_A23,,,EVENTOUT, +PortE,PE3,TRACED0,,,,TIM15_BKIN,,SAI1_SD_B,,SAI4_SD_B,,,,FMC_A19,,,EVENTOUT, +PortE,PE4,TRACED1,,SAI1_D2,DFSDM_DATIN3,TIM15_CH1N,SPI4_NSS,SAI1_FS_A,,SAI4_FS_A,,SAI4_D2,,FMC_A20,DCMI_D4,LCD_B0,EVENTOUT, +PortE,PE5,TRACED2,,SAI1_CK2,DFSDM_CKIN3,TIM15_CH1,SPI4_MISO,SAI1_SCK_A,,SAI4_SCK_A,,SAI4_CK2,,FMC_A21,DCMI_D6,LCD_G0,EVENTOUT, +PortE,PE6,TRACED3,TIM1_BKIN2,SAI1_D1,,TIM15_CH2,SPI4_MOSI,SAI1_SD_A,,SAI4_SD_A,SAI4_D1,SAI2_MCK_B,TIM1_BKIN2_COMP12,FMC_A22,DCMI_D7,LCD_G1,EVENTOUT, +PortE,PE7,,TIM1_ETR,,DFSDM_DATIN2,,,,UART7_RX,,,QUADSPI_BK2_IO0,,FMC_D4/FMC_DA4,,,EVENTOUT, +PortE,PE8,,TIM1_CH1N,,DFSDM_CKIN2,,,,UART7_TX,,,QUADSPI_BK2_IO1,,FMC_D5/FMC_DA5,COMP_2_OUT,,EVENTOUT, +PortE,PE9,,TIM1_CH1,,DFSDM_CKOUT,,,,UART7_RTS,,,QUADSPI_BK2_IO2,,FMC_D6/FMC_DA6,,,EVENTOUT, +PortE,PE10,,TIM1_CH2N,,DFSDM_DATIN4,,,,UART7_CTS,,,QUADSPI_BK2_IO3,,FMC_D7/FMC_DA7,,,EVENTOUT, +PortE,PE11,,TIM1_CH2,,DFSDM_CKIN4,,SPI4_NSS,,,,,SAI2_SD_B,,FMC_D8/FMC_DA8,,LCD_G3,EVENTOUT, +PortE,PE12,,TIM1_CH3N,,DFSDM_DATIN5,,SPI4_SCK,,,,,SAI2_SCK_B,,FMC_D9/FMC_DA9,COMP_1_OUT,LCD_B4,EVENTOUT, +PortE,PE13,,TIM1_CH3,,DFSDM_CKIN5,,SPI4_MISO,,,,,SAI2_FS_B,,FMC_D10/FMC_DA10,COMP_2_OUT,LCD_DE,EVENTOUT, +PortE,PE14,,TIM1_CH4,,,,SPI4_MOSI,,,,,SAI2_MCK_B,,FMC_D11/FMC_DA11,,LCD_CLK,EVENTOUT, +PortE,PE15,,TIM1_BKIN,,,,HDMI__TIM1_BKIN,,,,,,,FMC_D12/FMC_DA12,TIM1_BKIN_COMP12,LCD_R7,EVENTOUT, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT, +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT, +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT, +PortF,PF6,,TIM16_CH1,,,,SPI5_NSS,SAI1_SD_B,UART7_RX,SAI4_SD_B,QUADSPI_BK1_IO3,,,,,,EVENTOUT, +PortF,PF7,,TIM17_CH1,,,,SPI5_SCK,SAI1_MCLK_B,UART7_TX,SAI4_MCLK_B,QUADSPI_BK1_IO2,,,,,,EVENTOUT, +PortF,PF8,,TIM16_CH1N,,,,SPI5_MISO,SAI1_SCK_B,UART7_RTS,SAI4_SCK_B,TIM13_CH1,QUADSPI_BK1_IO0,,,,,EVENTOUT, +PortF,PF9,,TIM17_CH1N,,,,SPI5_MOSI,SAI1_FS_B,UART7_CTS,SAI4_FS_B,TIM14_CH1,QUADSPI_BK1_IO1,,,,,EVENTOUT, +PortF,PF10,,TIM16_BKIN,SAI1_D3,,,,,,,QUADSPI_CLK,SAI4_D3,,,DCMI_D11,LCD_DE,EVENTOUT, +PortF,PF11,,,,,,SPI5_MOSI,,,,,SAI2_SD_B,,FMC_SDNRAS,DCMI_D12,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT, +PortF,PF13,,,,DFSDM_DATIN6,I2C4_SMBA,,,,,,,,FMC_A7,,,EVENTOUT, +PortF,PF14,,,,DFSDM_CKIN6,I2C4_SCL,,,,,,,,FMC_A8,,,EVENTOUT, +PortF,PF15,,,,,I2C4_SDA,,,,,,,,FMC_A9,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,FMC_A10,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,FMC_A11,,,EVENTOUT, +PortG,PG2,,,,TIM8_BKIN,,,,,,,,TIM8_BKIN_COMP12,FMC_A12,,,EVENTOUT, +PortG,PG3,,,,TIM8_BKIN2,,,,,,,,TIM8_BKIN2_COMP12,FMC_A13,,,EVENTOUT, +PortG,PG4,,TIM1_BKIN2,,,,,,,,,,TIM1_BKIN2_COMP12,FMC_A14/FMC_BA0,,,EVENTOUT, +PortG,PG5,,TIM1_ETR,,,,,,,,,,,FMC_A15/FMC_BA1,,,EVENTOUT, +PortG,PG6,,TIM17_BKIN,HRTIM_CHE1,,,,,,,,QUADSPI_BK1_NCS,,FMC_NE3,DCMI_D12,LCD_R7,EVENTOUT, +PortG,PG7,,,HRTIM_CHE2,,,,SAI1_MCLK_A,USART6_CK,,,,,FMC_INT,DCMI_D13,LCD_CLK,EVENTOUT, +PortG,PG8,,,,TIM8_ETR,,SPI6_NSS,,USART6_RTS,SPDIFRX_IN2,,,ETH_PPS_OUT,FMC_SDCLK,,LCD_G7,EVENTOUT, +PortG,PG9,,,,,,SPI1_MISO/I2S1_SDI,,USART6_RX,SPDIFRX_IN3,QUADSPI_BK2_IO2,SAI2_FS_B,,FMC_NE2/FMC_NCE,DCMI_VSYNC,,EVENTOUT, +PortG,PG10,,,HRTIM_FLT5,,,SPI1_NSS/I2S1_WS,,,,LCD_G3,SAI2_SD_B,,FMC_NE3,DCMI_D2,LCD_B2,EVENTOUT, +PortG,PG11,,,HRTIM_EEV4,,,SPI1_SCK/I2S1_CK,,,SPDIFRX_IN0,,SDMMC2_D2,ETH_MII_TX_EN/ETH_RMII_TX_EN,,DCMI_D3,LCD_B3,EVENTOUT, +PortG,PG12,,LPTIM1_IN1,HRTIM_EEV5,,,SPI6_MISO,,USART6_RTS,SPDIFRX_IN1,LCD_B4,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_NE4,,LCD_B1,EVENTOUT, +PortG,PG13,TRACED0,LPTIM1_OUT,HRTIM_EEV10,,,SPI6_SCK,,USART6_CTS_NSS,,,,ETH_MII_TXD0/ETH_RMII_TXD0,FMC_A24,,LCD_R0,EVENTOUT, +PortG,PG14,TRACED1,LPTIM1_ETR,,,,SPI6_MOSI,,USART6_TX,,QUADSPI_BK2_IO3,,ETH_MII_TXD1/ETH_RMII_TXD1,FMC_A25,,LCD_B0,EVENTOUT, +PortG,PG15,,,,,,,,USART6_CTS_NSS,,,,,FMC_SDNCAS,DCMI_D13,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH2,,LPTIM1_IN2,,,,,,,,QUADSPI_BK2_IO0,SAI2_SCK_B,ETH_MII_CRS,FMC_SDCKE0,,LCD_R0,EVENTOUT, +PortH,PH3,,,,,,,,,,QUADSPI_BK2_IO1,SAI2_MCK_B,ETH_MII_COL,FMC_SDNE0,,LCD_R1,EVENTOUT, +PortH,PH4,,,,,I2C2_SCL,,,,,LCD_G5,OTG_HS_ULPI_NXT,,,,LCD_G4,EVENTOUT, +PortH,PH5,,,,,I2C2_SDA,SPI5_NSS,,,,,,,FMC_SDNWE,,,EVENTOUT, +PortH,PH6,,,TIM12_CH1,,I2C2_SMBA,SPI5_SCK,,,,,,ETH_MII_RXD2,FMC_SDNE1,DCMI_D8,,EVENTOUT, +PortH,PH7,,,,,I2C3_SCL,SPI5_MISO,,,,,,ETH_MII_RXD3,FMC_SDCKE1,DCMI_D9,,EVENTOUT, +PortH,PH8,,,TIM5_ETR,,I2C3_SDA,,,,,,,,FMC_D16,DCMI_HSYNC,LCD_R2,EVENTOUT, +PortH,PH9,,,TIM12_CH2,,I2C3_SMBA,,,,,,,,FMC_D17,DCMI_D0,LCD_R3,EVENTOUT, +PortH,PH10,,,TIM5_CH1,,I2C4_SMBA,,,,,,,,FMC_D18,DCMI_D1,LCD_R4,EVENTOUT, +PortH,PH11,,,TIM5_CH2,,I2C4_SCL,,,,,,,,FMC_D19,DCMI_D2,LCD_R5,EVENTOUT, +PortH,PH12,,,TIM5_CH3,,I2C4_SDA,,,,,,,,FMC_D20,DCMI_D3,LCD_R6,EVENTOUT, +PortH,PH13,,,,TIM8_CH1N,,,,,UART4_TX,CAN1_TX,,,FMC_D21,,LCD_G2,EVENTOUT, +PortH,PH14,,,,TIM8_CH2N,,,,,UART4_RX,CAN1_RX,,,FMC_D22,DCMI_D4,LCD_G3,EVENTOUT, +PortH,PH15,,,,TIM8_CH3N,,,,,,CAN1_TXFD,,,FMC_D23,DCMI_D11,LCD_G4,EVENTOUT, +PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,CAN1_RXFD,,,FMC_D24,DCMI_D13,LCD_G5,EVENTOUT, +PortI,PI1,,,,TIM8_BKIN2,,SPI2_SCK/I2S2_CK,,,,,,TIM8_BKIN2_COMP12,FMC_D25,DCMI_D8,LCD_G6,EVENTOUT, +PortI,PI2,,,,TIM8_CH4,,SPI2_MISO/I2S2_SDI,,,,,,,FMC_D26,DCMI_D9,LCD_G7,EVENTOUT, +PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SDO,,,,,,,FMC_D27,DCMI_D10,,EVENTOUT, +PortI,PI4,,,,TIM8_BKIN,,,,,,,SAI2_MCK_A,TIM8_BKIN_COMP12,FMC_NBL2,DCMI_D5,LCD_B4,EVENTOUT, +PortI,PI5,,,,TIM8_CH1,,,,,,,SAI2_SCK_A,,FMC_NBL3,DCMI_VSYNC,LCD_B5,EVENTOUT, +PortI,PI6,,,,TIM8_CH2,,,,,,,SAI2_SD_A,,FMC_D28,DCMI_D6,LCD_B6,EVENTOUT, +PortI,PI7,,,,TIM8_CH3,,,,,,,SAI2_FS_A,,FMC_D29,DCMI_D7,LCD_B7,EVENTOUT, +PortI,PI8,,,,,,,,,,,,,,,,EVENTOUT, +PortI,PI9,,,,,,,,,UART4_RX,CAN1_RX,,,FMC_D30,,LCD_VSYNC,EVENTOUT, +PortI,PI10,,,,,,,,,,CAN1_RXFD,,ETH_MII_RX_ER,FMC_D31,,LCD_HSYNC,EVENTOUT, +PortI,PI11,,,,,,,,,,LCD_G6,OTG_HS_ULPI_DIR,,,,,EVENTOUT, +PortI,PI12,,,,,,,,,,,,ETH_TX_ER,,,LCD_HSYNC,EVENTOUT, +PortI,PI13,,,,,,,,,,,,,,,LCD_VSYNC,EVENTOUT, +PortI,PI14,,,,,,,,,,,,,,,LCD_CLK,EVENTOUT, +PortI,PI15,,,,,,,,,,LCD_G2,,,,,LCD_R0,EVENTOUT, +PortJ,PJ0,,,,,,,,,,LCD_R7,,,,,LCD_R1,EVENTOUT, +PortJ,PJ1,,,,,,,,,,,,,,,LCD_R2,EVENTOUT, +PortJ,PJ2,,,,,,,,,,,,,,,LCD_R3,EVENTOUT, +PortJ,PJ3,,,,,,,,,,,,,,,LCD_R4,EVENTOUT, +PortJ,PJ4,,,,,,,,,,,,,,,LCD_R5,EVENTOUT, +PortJ,PJ5,,,,,,,,,,,,,,,LCD_R6,EVENTOUT, +PortJ,PJ6,,,,TIM8_CH2,,,,,,,,,,,LCD_R7,EVENTOUT, +PortJ,PJ7,TRGIN,,,TIM8_CH2N,,,,,,,,,,,LCD_G0,EVENTOUT, +PortJ,PJ8,,TIM1_CH3N,,TIM8_CH1,,,,,UART8_TX,,,,,,LCD_G1,EVENTOUT, +PortJ,PJ9,,TIM1_CH3,,TIM8_CH1N,,,,,UART8_RX,,,,,,LCD_G2,EVENTOUT, +PortJ,PJ10,,TIM1_CH2N,,TIM8_CH2,,SPI5_MOSI,,,,,,,,,LCD_G3,EVENTOUT, +PortJ,PJ11,,TIM1_CH2,,TIM8_CH2N,,SPI5_MISO,,,,,,,,,LCD_G4,EVENTOUT, +PortJ,PJ12,TRGOUT,,,,,,,,,LCD_G3,,,,,LCD_B0,EVENTOUT, +PortJ,PJ13,,,,,,,,,,LCD_B4,,,,,LCD_B1,EVENTOUT, +PortJ,PJ14,,,,,,,,,,,,,,,LCD_B2,EVENTOUT, +PortJ,PJ15,,,,,,,,,,,,,,,LCD_B3,EVENTOUT, +PortK,PK0,,TIM1_CH1N,,TIM8_CH3,,SPI5_SCK,,,,,,,,,LCD_G5,EVENTOUT, +PortK,PK1,,TIM1_CH1,,TIM8_CH3N,,SPI5_NSS,,,,,,,,,LCD_G6,EVENTOUT, +PortK,PK2,,TIM1_BKIN,,TIM8_BKIN,,,,,,,TIM8_BKIN_COMP12,TIM1_BKIN_COMP12,,,LCD_G7,EVENTOUT, +PortK,PK3,,,,,,,,,,,,,,,LCD_B4,EVENTOUT, +PortK,PK4,,,,,,,,,,,,,,,LCD_B5,EVENTOUT, +PortK,PK5,,,,,,,,,,,,,,,LCD_B6,EVENTOUT, +PortK,PK6,,,,,,,,,,,,,,,LCD_B7,EVENTOUT, +PortK,PK7,,,,,,,,,,,,,,,LCD_DE,EVENTOUT, diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld index 11b2972ad..76f94444e 100644 --- a/ports/stm32/boards/stm32l476xe.ld +++ b/ports/stm32/boards/stm32l476xe.ld @@ -22,9 +22,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld index a94fa2750..83bb23901 100644 --- a/ports/stm32/boards/stm32l476xg.ld +++ b/ports/stm32/boards/stm32l476xg.ld @@ -24,9 +24,6 @@ _minimum_heap_size = 16K; aligned for a call. */ _estack = ORIGIN(RAM) + LENGTH(RAM); -/* define common sections and symbols */ -INCLUDE common.ld - /* RAM extents for the garbage collector */ _ram_start = ORIGIN(RAM); _ram_end = ORIGIN(RAM) + LENGTH(RAM); diff --git a/ports/stm32/bufhelper.h b/ports/stm32/bufhelper.h index c1967bf43..12c79c2fd 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 25a608ce9..bc4f1092c 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; @@ -95,6 +108,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { uint32_t GPIO_Pin = 0; uint8_t GPIO_AF_CANx = 0; GPIO_TypeDef* GPIO_Port = NULL; + uint32_t sce_irq = 0; switch (can_obj->can_id) { // CAN1 is on RX,TX = Y3,Y4 = PB9,PB9 @@ -103,18 +117,22 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { GPIO_AF_CANx = GPIO_AF9_CAN1; GPIO_Port = GPIOB; GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9; + sce_irq = CAN1_SCE_IRQn; __CAN1_CLK_ENABLE(); break; + #if defined(CAN2) // CAN2 is on RX,TX = Y5,Y6 = PB12,PB13 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; __CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well __CAN2_CLK_ENABLE(); break; + #endif default: return false; @@ -123,7 +141,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { // init GPIO GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = GPIO_Pin; - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Alternate = GPIO_AF_CANx; @@ -134,6 +152,14 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { HAL_CAN_Init(&can_obj->can); can_obj->is_enabled = true; + can_obj->num_error_warning = 0; + can_obj->num_error_passive = 0; + can_obj->num_bus_off = 0; + + __HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG); + + HAL_NVIC_SetPriority(sce_irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN); + HAL_NVIC_EnableIRQ(sce_irq); return true; } @@ -170,6 +196,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 +339,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 +346,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 +364,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 +483,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 +595,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 +611,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 +620,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 +637,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 +647,20 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send); -/// \method recv(fifo, *, timeout=5000) +/// \method recv(fifo, list=None, *, timeout=5000) /// /// Receive data on the bus: /// /// - `fifo` is an integer, which is the FIFO to receive on +/// - `list` if not None is a list with at least 4 elements /// - `timeout` is the timeout in milliseconds to wait for the receive. /// /// Return value: buffer of data bytes. STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_fifo, ARG_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 +671,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 == (0x80 | BYTEARRAY_TYPECODE) + || (mv->typecode | 0x20) == (0x80 | 'b'))) { + mp_raise_ValueError(NULL); + } + mv->len = rx_msg.DLC; + memcpy(mv->items, &rx_msg.Data[0], rx_msg.DLC); } - tuple->items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; - tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); - vstr_t vstr; - vstr_init_len(&vstr, rx_msg.DLC); - for (mp_uint_t i = 0; i < rx_msg.DLC; i++) { - vstr.buf[i] = rx_msg.Data[i]; // Data is uint32_t but holds only 1 byte + + // Populate the first 3 values of the tuple/list + if (rx_msg.IDE == CAN_ID_STD) { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); + } else { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); } - tuple->items[3] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); - return tuple; + items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; + items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); + + // Return the result + return ret_obj; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv); @@ -617,6 +787,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 +806,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 +836,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 +854,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 +879,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,11 +931,13 @@ STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t *callback = callback_in; } else if (mp_obj_is_callable(callback_in)) { *callback = callback_in; - uint32_t irq; + uint32_t irq = 0; if (self->can_id == PYB_CAN_1) { irq = (fifo == 0) ? CAN1_RX0_IRQn : CAN1_RX1_IRQn; + #if defined(CAN2) } else { irq = (fifo == 0) ? CAN2_RX0_IRQn : CAN2_RX1_IRQn; + #endif } HAL_NVIC_SetPriority(irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN); HAL_NVIC_EnableIRQ(irq); @@ -780,6 +953,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 +975,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 +1064,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 860012813..54e7deaa5 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 268b1bcfb..9d8d7a872 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -33,7 +33,6 @@ #include "dac.h" #include "dma.h" #include "pin.h" -#include "genhdr/pins.h" /// \moduleref pyb /// \class DAC - digital to analog conversion @@ -159,9 +158,9 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // DAC peripheral clock - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) __DAC_CLK_ENABLE(); - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) __HAL_RCC_DAC1_CLK_ENABLE(); #else #error Unsupported Processor @@ -213,9 +212,9 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, size_t n_args, size_ dac_id = mp_obj_get_int(args[0]); } else { const pin_obj_t *pin = pin_find(args[0]); - if (pin == &pin_A4) { + if (pin == pin_A4) { dac_id = 1; - } else if (pin == &pin_A5) { + } else if (pin == pin_A5) { dac_id = 2; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Pin(%q) doesn't have DAC capabilities", pin->name)); diff --git a/ports/stm32/dac.h b/ports/stm32/dac.h index f487f52a9..1d8f0ab61 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 dde7d730a..dd93a8115 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -53,9 +53,9 @@ typedef enum { } dma_id_t; typedef struct _dma_descr_t { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) DMA_Stream_TypeDef *instance; - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) DMA_Channel_TypeDef *instance; #else #error "Unsupported Processor" @@ -69,9 +69,9 @@ typedef struct _dma_descr_t { // Default parameters to dma_init() shared by spi and i2c; Channel and Direction // vary depending on the peripheral instance so they get passed separately static const DMA_InitTypeDef dma_init_struct_spi_i2c = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .Channel = 0, - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) .Request = 0, #endif .Direction = 0, @@ -81,7 +81,7 @@ static const DMA_InitTypeDef dma_init_struct_spi_i2c = { .MemDataAlignment = DMA_MDATAALIGN_BYTE, .Mode = DMA_NORMAL, .Priority = DMA_PRIORITY_LOW, - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) .FIFOMode = DMA_FIFOMODE_DISABLE, .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, .MemBurst = DMA_MBURST_INC4, @@ -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,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = { }; #endif -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) #define NCONTROLLERS (2) #define NSTREAMS_PER_CONTROLLER (8) @@ -161,7 +161,7 @@ static const DMA_InitTypeDef dma_init_struct_dac = { // DMA1 streams const dma_descr_t dma_I2C_1_RX = { DMA1_Stream0, DMA_CHANNEL_1, DMA_PERIPH_TO_MEMORY, dma_id_0, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_3_RX = { DMA1_Stream2, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) const dma_descr_t dma_I2C_4_RX = { DMA1_Stream2, DMA_CHANNEL_2, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; #endif const dma_descr_t dma_I2C_3_RX = { DMA1_Stream2, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; @@ -169,7 +169,7 @@ const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_CHANNEL_7, DMA_PERIPH_TO_ME const dma_descr_t dma_SPI_2_RX = { DMA1_Stream3, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_2_TX = { DMA1_Stream4, DMA_CHANNEL_0, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; const dma_descr_t dma_I2C_3_TX = { DMA1_Stream4, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) const dma_descr_t dma_I2C_4_TX = { DMA1_Stream5, DMA_CHANNEL_2, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c }; #endif #if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC @@ -185,7 +185,7 @@ const dma_descr_t dma_I2C_1_TX = { DMA1_Stream6, DMA_CHANNEL_1, DMA_MEMORY_TO_PE */ // DMA2 streams -#if defined(MCU_SERIES_F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD const dma_descr_t dma_SDMMC_2_RX= { DMA2_Stream0, DMA_CHANNEL_11, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_sdio }; #endif const dma_descr_t dma_SPI_1_RX = { DMA2_Stream2, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_10, &dma_init_struct_spi_i2c }; @@ -198,7 +198,7 @@ const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, DMA_MEMORY_TO_PE const dma_descr_t dma_SPI_4_TX = { DMA2_Stream4, DMA_CHANNEL_5, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_6_TX = { DMA2_Stream5, DMA_CHANNEL_1, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; const dma_descr_t dma_SPI_1_TX = { DMA2_Stream5, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; -#if defined(MCU_SERIES_F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD +#if defined(STM32F7) && defined(SDMMC2) && MICROPY_HW_HAS_SDCARD const dma_descr_t dma_SDMMC_2_TX= { DMA2_Stream5, DMA_CHANNEL_11, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_sdio }; #endif const dma_descr_t dma_SPI_6_RX = { DMA2_Stream6, DMA_CHANNEL_1, DMA_PERIPH_TO_MEMORY, dma_id_14, &dma_init_struct_spi_i2c }; @@ -233,7 +233,7 @@ static const uint8_t dma_irqn[NSTREAM] = { DMA2_Stream7_IRQn, }; -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) #define NCONTROLLERS (2) #define NSTREAMS_PER_CONTROLLER (7) @@ -308,6 +308,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_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_REQUEST_DAC2_TX, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_3_TX = { DMA1_Stream7, DMA_REQUEST_SPI3_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_REQUEST_I2C1_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Stream7, DMA_REQUEST_I2C2_TX, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; + +// DMA2 streams +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}; @@ -320,7 +384,7 @@ volatile dma_idle_count_t dma_idle; #define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0) #define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0) -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(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 +403,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 +437,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 +448,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,7 +473,7 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void dma->Instance = dma_descr->instance; dma->Init = *dma_descr->init; dma->Init.Direction = dma_descr->transfer_direction; - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) || defined(STM32H7) dma->Init.Request = dma_descr->sub_instance; #else dma->Init.Channel = dma_descr->sub_instance; @@ -448,13 +512,12 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ } else { // only necessary initialization dma->State = HAL_DMA_STATE_READY; - -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#if defined(STM32F4) || defined(STM32F7) // calculate DMA base address and bitshift to be used in IRQ handler extern uint32_t DMA_CalcBaseAndBitshift(DMA_HandleTypeDef *hdma); DMA_CalcBaseAndBitshift(dma); -#elif defined(MCU_SERIES_L4) +#elif defined(STM32L4) // The memset() just above will have cleared these private vars from the HAL. // Recalculate them now. dma->DmaBaseAddress = (DMA_TypeDef *)((uint32_t)dma->Instance & ~0xff); @@ -501,9 +564,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 55fb62175..f265d6035 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(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 41943f1cd..9fe53a1a3 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) @@ -132,7 +137,7 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) PVD_PVM_IRQn, #else PVD_IRQn, @@ -203,7 +208,7 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca exti.Pin = pin->pin_mask; exti.Mode = mode; exti.Pull = pull; - exti.Speed = GPIO_SPEED_FAST; + exti.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(pin->gpio, &exti); // Calling HAL_GPIO_Init does an implicit extint_enable @@ -277,13 +282,21 @@ void extint_enable(uint line) { if (line >= EXTI_NUM_VECTORS) { return; } - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) || defined(STM32H7) // The Cortex-M7 doesn't have bitband support. mp_uint_t irq_state = disable_irq(); if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) { + #if defined(STM32H7) + EXTI_D1->IMR1 |= (1 << line); + #else EXTI->IMR |= (1 << line); + #endif } else { + #if defined(STM32H7) + EXTI_D1->EMR1 |= (1 << line); + #else EXTI->EMR |= (1 << line); + #endif } enable_irq(irq_state); #else @@ -299,11 +312,16 @@ void extint_disable(uint line) { return; } - #if defined(MCU_SERIES_F7) + #if defined(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 +337,7 @@ void extint_swint(uint line) { return; } // we need 0 to 1 transition to trigger the interrupt -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) || defined(STM32H7) EXTI->SWIER1 &= ~(1 << line); EXTI->SWIER1 |= (1 << line); #else @@ -368,7 +386,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj, extint_obj_swint); /// \classmethod regs() /// Dump the values of the EXTI registers. STATIC mp_obj_t extint_regs(void) { - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) printf("EXTI_IMR1 %08lx\n", EXTI->IMR1); printf("EXTI_IMR2 %08lx\n", EXTI->IMR2); printf("EXTI_EMR1 %08lx\n", EXTI->EMR1); @@ -381,6 +399,25 @@ STATIC mp_obj_t extint_regs(void) { printf("EXTI_SWIER2 %08lx\n", EXTI->SWIER2); printf("EXTI_PR1 %08lx\n", EXTI->PR1); printf("EXTI_PR2 %08lx\n", EXTI->PR2); + #elif defined(STM32H7) + printf("EXTI_IMR1 %08lx\n", EXTI_D1->IMR1); + printf("EXTI_IMR2 %08lx\n", EXTI_D1->IMR2); + printf("EXTI_IMR3 %08lx\n", EXTI_D1->IMR3); + printf("EXTI_EMR1 %08lx\n", EXTI_D1->EMR1); + printf("EXTI_EMR2 %08lx\n", EXTI_D1->EMR2); + printf("EXTI_EMR3 %08lx\n", EXTI_D1->EMR3); + printf("EXTI_RTSR1 %08lx\n", EXTI->RTSR1); + printf("EXTI_RTSR2 %08lx\n", EXTI->RTSR2); + printf("EXTI_RTSR3 %08lx\n", EXTI->RTSR3); + printf("EXTI_FTSR1 %08lx\n", EXTI->FTSR1); + printf("EXTI_FTSR2 %08lx\n", EXTI->FTSR2); + printf("EXTI_FTSR3 %08lx\n", EXTI->FTSR3); + printf("EXTI_SWIER1 %08lx\n", EXTI->SWIER1); + printf("EXTI_SWIER2 %08lx\n", EXTI->SWIER2); + printf("EXTI_SWIER3 %08lx\n", EXTI->SWIER3); + printf("EXTI_PR1 %08lx\n", EXTI_D1->PR1); + printf("EXTI_PR2 %08lx\n", EXTI_D1->PR2); + printf("EXTI_PR3 %08lx\n", EXTI_D1->PR3); #else printf("EXTI_IMR %08lx\n", EXTI->IMR); printf("EXTI_EMR %08lx\n", EXTI->EMR); diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h index 846790b9b..c4a4ae6bb 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 17ec3f726..d0e311ed7 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 bebb3a161..214d10fdb 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -34,7 +34,7 @@ typedef struct { uint32_t sector_count; } flash_layout_t; -#if defined(MCU_SERIES_F4) +#if defined(STM32F4) static const flash_layout_t flash_layout[] = { { 0x08000000, 0x04000, 4 }, @@ -50,7 +50,7 @@ static const flash_layout_t flash_layout[] = { #endif }; -#elif defined(MCU_SERIES_F7) +#elif defined(STM32F7) // FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to // FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7 @@ -62,21 +62,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, 8 }, +}; + #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 +103,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 +114,7 @@ static uint32_t get_page(uint32_t addr) { return (addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE; } } +#endif #endif @@ -141,7 +153,7 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) FLASH_EraseInitTypeDef EraseInitStruct; - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); // erase the sector(s) @@ -153,12 +165,19 @@ void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) EraseInitStruct.NbPages = get_page(flash_dest + 4 * num_word32 - 1) - EraseInitStruct.Page + 1;; #else // Clear pending flags (if any) + #if defined(STM32H7) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS_BANK1 | FLASH_FLAG_ALL_ERRORS_BANK2); + #else __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); + #endif // erase the sector(s) EraseInitStruct.TypeErase = TYPEERASE_SECTORS; EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + #if defined(STM32H7) + EraseInitStruct.Banks = get_bank(flash_dest); + #endif EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL); EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1; #endif @@ -201,7 +220,7 @@ void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word3 */ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) // program the flash uint64 by uint64 for (int i = 0; i < num_word32 / 2; i++) { @@ -224,11 +243,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 688e70a3c..d69f6e27f 100644 --- a/ports/stm32/flash.h +++ b/ports/stm32/flash.h @@ -23,11 +23,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_FLASH_H -#define MICROPY_INCLUDED_STMHAL_FLASH_H +#ifndef MICROPY_INCLUDED_STM32_FLASH_H +#define MICROPY_INCLUDED_STM32_FLASH_H uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size); void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); -#endif // MICROPY_INCLUDED_STMHAL_FLASH_H +#endif // MICROPY_INCLUDED_STM32_FLASH_H diff --git a/ports/stm32/flashbdev.c b/ports/stm32/flashbdev.c new file mode 100644 index 000000000..4245dd1ec --- /dev/null +++ b/ports/stm32/flashbdev.c @@ -0,0 +1,267 @@ +/* + * 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) + +extern uint8_t _flash_fs_start; +extern uint8_t _flash_fs_end; + +// The STM32L475/6 doesn't have CCRAM, so we use the 32K SRAM2 for this. +#define CACHE_MEM_START_ADDR (0x10000000) // SRAM2 data RAM, 32k +#define FLASH_SECTOR_SIZE_MAX (0x00800) // 2k max +#define FLASH_MEM_SEG1_START_ADDR ((long)&_flash_fs_start) +#define FLASH_MEM_SEG1_NUM_BLOCKS ((&_flash_fs_end - &_flash_fs_start) / 512) + +#else +#error "no internal flash storage support for this MCU" +#endif + +#if !defined(FLASH_MEM_SEG2_START_ADDR) +#define FLASH_MEM_SEG2_START_ADDR (0) // no second segment +#define FLASH_MEM_SEG2_NUM_BLOCKS (0) // no second segment +#endif + +#define FLASH_FLAG_DIRTY (1) +#define FLASH_FLAG_FORCE_WRITE (2) +#define FLASH_FLAG_ERASED (4) +static __IO uint8_t flash_flags = 0; +static uint32_t flash_cache_sector_id; +static uint32_t flash_cache_sector_start; +static uint32_t flash_cache_sector_size; +static uint32_t flash_tick_counter_last_write; + +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, (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) || 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 8b0cc9cb0..cdc4e73a7 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 1b64a51a6..25a74a306 100644 --- a/ports/stm32/gccollect.h +++ b/ports/stm32/gccollect.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_GCCOLLECT_H -#define MICROPY_INCLUDED_STMHAL_GCCOLLECT_H +#ifndef MICROPY_INCLUDED_STM32_GCCOLLECT_H +#define MICROPY_INCLUDED_STM32_GCCOLLECT_H // variables defining memory layout // (these probably belong somewhere else...) @@ -40,4 +40,4 @@ extern uint32_t _heap_end; extern uint32_t _estack; extern uint32_t _ram_end; -#endif // MICROPY_INCLUDED_STMHAL_GCCOLLECT_H +#endif // MICROPY_INCLUDED_STM32_GCCOLLECT_H diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index b22787cab..d4f608007 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -31,11 +31,12 @@ #include "py/mphal.h" #include "irq.h" #include "pin.h" -#include "genhdr/pins.h" #include "bufhelper.h" #include "dma.h" #include "i2c.h" +#if MICROPY_HW_ENABLE_HW_I2C + /// \moduleref pyb /// \class I2C - a two-wire serial protocol /// @@ -87,6 +88,10 @@ #define PYB_I2C_MASTER (0) #define PYB_I2C_SLAVE (1) +#define PYB_I2C_SPEED_STANDARD (100000L) +#define PYB_I2C_SPEED_FULL (400000L) +#define PYB_I2C_SPEED_FAST (1000000L) + #if defined(MICROPY_HW_I2C1_SCL) I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL}; #endif @@ -125,37 +130,54 @@ const pyb_i2c_obj_t pyb_i2c_obj[] = { #endif }; -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) +#if defined(STM32F7) || defined(STM32L4) || defined(STM32H7) -// The STM32F0, F3, F7 and L4 use a TIMINGR register rather than ClockSpeed and +// The STM32F0, F3, F7, H7 and L4 use a TIMINGR register rather than ClockSpeed and // DutyCycle. #if defined(STM32F746xx) // The value 0x40912732 was obtained from the DISCOVERY_I2Cx_TIMING constant // defined in the STM32F7Cube file Drivers/BSP/STM32F746G-Discovery/stm32f7456g_discovery.h -#define MICROPY_HW_I2C_BAUDRATE_TIMING {{100000, 0x40912732}} -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (100000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (100000) +#define MICROPY_HW_I2C_BAUDRATE_TIMING { \ + {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(STM32F767xx) || defined(STM32F769xx) +#elif defined(STM32F722xx) || defined(STM32F723xx) \ + || defined(STM32F732xx) || defined(STM32F733xx) \ + || defined(STM32F767xx) || defined(STM32F769xx) // These timing values are for f_I2CCLK=54MHz and are only approximate #define MICROPY_HW_I2C_BAUDRATE_TIMING { \ - {100000, 0xb0420f13}, \ - {400000, 0x70330309}, \ - {1000000, 0x50100103}, \ + {PYB_I2C_SPEED_STANDARD, 0xb0420f13}, \ + {PYB_I2C_SPEED_FULL, 0x70330309}, \ + {PYB_I2C_SPEED_FAST, 0x50100103}, \ } -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (1000000) +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FAST) -#elif defined(MCU_SERIES_L4) +#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 {{100000, 0x90112626}} -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (100000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (100000) +#define MICROPY_HW_I2C_BAUDRATE_TIMING {{PYB_I2C_SPEED_STANDARD, 0x90112626}} +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_STANDARD) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_STANDARD) #else #error "no I2C timings for this MCU" @@ -179,9 +201,9 @@ STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { "Unsupported I2C baudrate: %lu", baudrate)); } -uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) { +uint32_t i2c_get_baudrate(I2C_HandleTypeDef *i2c) { for (int i = 0; i < NUM_BAUDRATE_TIMINGS; i++) { - if (pyb_i2c_baudrate_timing[i].timing == init->Timing) { + if (pyb_i2c_baudrate_timing[i].timing == i2c->Init.Timing) { return pyb_i2c_baudrate_timing[i].baudrate; } } @@ -190,37 +212,42 @@ uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) { #else -#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (400000) -#define MICROPY_HW_I2C_BAUDRATE_MAX (400000) +#define MICROPY_HW_I2C_BAUDRATE_DEFAULT (PYB_I2C_SPEED_FULL) +#define MICROPY_HW_I2C_BAUDRATE_MAX (PYB_I2C_SPEED_FULL) STATIC void i2c_set_baudrate(I2C_InitTypeDef *init, uint32_t baudrate) { init->ClockSpeed = baudrate; init->DutyCycle = I2C_DUTYCYCLE_16_9; } -uint32_t i2c_get_baudrate(I2C_InitTypeDef *init) { - return init->ClockSpeed; +uint32_t i2c_get_baudrate(I2C_HandleTypeDef *i2c) { + uint32_t pfreq = i2c->Instance->CR2 & 0x3f; + uint32_t ccr = i2c->Instance->CCR & 0xfff; + if (i2c->Instance->CCR & 0x8000) { + // Fast mode, assume duty cycle of 16/9 + return pfreq * 40000 / ccr; + } else { + // Standard mode + return pfreq * 500000 / ccr; + } } #endif void i2c_init0(void) { - // reset the I2C1 handles + // Initialise the I2C handles. + // The structs live on the BSS so all other fields will be zero after a reset. #if defined(MICROPY_HW_I2C1_SCL) - memset(&I2CHandle1, 0, sizeof(I2C_HandleTypeDef)); I2CHandle1.Instance = I2C1; #endif #if defined(MICROPY_HW_I2C2_SCL) - memset(&I2CHandle2, 0, sizeof(I2C_HandleTypeDef)); I2CHandle2.Instance = I2C2; #endif #if defined(MICROPY_HW_I2C3_SCL) - memset(&I2CHandle3, 0, sizeof(I2C_HandleTypeDef)); I2CHandle3.Instance = I2C3; #endif #if defined(MICROPY_HW_I2C4_SCL) - memset(&I2CHandle4, 0, sizeof(I2C_HandleTypeDef)); - I2CHandle3.Instance = I2C4; + I2CHandle4.Instance = I2C4; #endif } @@ -233,30 +260,30 @@ void i2c_init(I2C_HandleTypeDef *i2c) { #if defined(MICROPY_HW_I2C1_SCL) } else if (i2c == &I2CHandle1) { i2c_unit = 1; - scl_pin = &MICROPY_HW_I2C1_SCL; - sda_pin = &MICROPY_HW_I2C1_SDA; + scl_pin = MICROPY_HW_I2C1_SCL; + sda_pin = MICROPY_HW_I2C1_SDA; __I2C1_CLK_ENABLE(); #endif #if defined(MICROPY_HW_I2C2_SCL) } else if (i2c == &I2CHandle2) { i2c_unit = 2; - scl_pin = &MICROPY_HW_I2C2_SCL; - sda_pin = &MICROPY_HW_I2C2_SDA; + scl_pin = MICROPY_HW_I2C2_SCL; + sda_pin = MICROPY_HW_I2C2_SDA; __I2C2_CLK_ENABLE(); #endif #if defined(MICROPY_HW_I2C3_SCL) } else if (i2c == &I2CHandle3) { i2c_unit = 3; - scl_pin = &MICROPY_HW_I2C3_SCL; - sda_pin = &MICROPY_HW_I2C3_SDA; + scl_pin = MICROPY_HW_I2C3_SCL; + sda_pin = MICROPY_HW_I2C3_SDA; __I2C3_CLK_ENABLE(); #endif #if defined(MICROPY_HW_I2C4_SCL) } else if (i2c == &I2CHandle4) { i2c_unit = 4; - scl_pin = &MICROPY_HW_I2C4_SCL; - sda_pin = &MICROPY_HW_I2C4_SDA; - __I2C3_CLK_ENABLE(); + scl_pin = MICROPY_HW_I2C4_SCL; + sda_pin = MICROPY_HW_I2C4_SDA; + __I2C4_CLK_ENABLE(); #endif } else { // I2C does not exist for this board (shouldn't get here, should be checked by caller) @@ -407,7 +434,7 @@ void i2c_ev_irq_handler(mp_uint_t i2c_id) { return; } - #if defined(MCU_SERIES_F4) + #if defined(STM32F4) if (hi2c->Instance->SR1 & I2C_FLAG_BTF && hi2c->State == HAL_I2C_STATE_BUSY_TX) { if (hi2c->XferCount != 0U) { @@ -459,7 +486,7 @@ void i2c_er_irq_handler(mp_uint_t i2c_id) { return; } - #if defined(MCU_SERIES_F4) + #if defined(STM32F4) uint32_t sr1 = hi2c->Instance->SR1; @@ -536,7 +563,7 @@ STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki mp_printf(print, "I2C(%u)", i2c_num); } else { if (in_master_mode(self)) { - mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, i2c_get_baudrate(&self->i2c->Init)); + mp_printf(print, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, i2c_get_baudrate(self->i2c)); } else { mp_printf(print, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f); } @@ -1033,3 +1060,5 @@ const mp_obj_type_t pyb_i2c_type = { .make_new = pyb_i2c_make_new, .locals_dict = (mp_obj_dict_t*)&pyb_i2c_locals_dict, }; + +#endif // MICROPY_HW_ENABLE_HW_I2C diff --git a/ports/stm32/i2c.h b/ports/stm32/i2c.h index 6affe3973..e17621f7c 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" @@ -48,8 +48,8 @@ extern const pyb_i2c_obj_t pyb_i2c_obj[4]; void i2c_init0(void); void i2c_init(I2C_HandleTypeDef *i2c); void i2c_init_freq(const pyb_i2c_obj_t *self, mp_int_t freq); -uint32_t i2c_get_baudrate(I2C_InitTypeDef *init); +uint32_t i2c_get_baudrate(I2C_HandleTypeDef *i2c); void i2c_ev_irq_handler(mp_uint_t i2c_id); void i2c_er_irq_handler(mp_uint_t i2c_id); -#endif // MICROPY_INCLUDED_STMHAL_I2C_H +#endif // MICROPY_INCLUDED_STM32_I2C_H diff --git a/ports/stm32/irq.h b/ports/stm32/irq.h index 2cf58639e..d0bb49c52 100644 --- a/ports/stm32/irq.h +++ b/ports/stm32/irq.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_IRQ_H -#define MICROPY_INCLUDED_STMHAL_IRQ_H +#ifndef MICROPY_INCLUDED_STM32_IRQ_H +#define MICROPY_INCLUDED_STM32_IRQ_H // these states correspond to values from query_irq, enable_irq and disable_irq #define IRQ_STATE_DISABLED (0x00000001) @@ -149,4 +149,4 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); #define IRQ_PRI_RTC_WKUP 15 #define IRQ_SUBPRI_RTC_WKUP 0 -#endif // MICROPY_INCLUDED_STMHAL_IRQ_H +#endif // MICROPY_INCLUDED_STM32_IRQ_H diff --git a/ports/stm32/lcd.c b/ports/stm32/lcd.c index 488df1699..10fb54eb5 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 c0d9bd97d..98f904848 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 9bbcaa6b3..6586f9213 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 diff --git a/ports/stm32/led.h b/ports/stm32/led.h index 2c872e9c5..1cc96b75a 100644 --- a/ports/stm32/led.h +++ b/ports/stm32/led.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_LED_H -#define MICROPY_INCLUDED_STMHAL_LED_H +#ifndef MICROPY_INCLUDED_STM32_LED_H +#define MICROPY_INCLUDED_STM32_LED_H typedef enum { PYB_LED_RED = 1, @@ -40,4 +40,4 @@ void led_debug(int value, int delay); extern const mp_obj_type_t pyb_led_type; -#endif // MICROPY_INCLUDED_STMHAL_LED_H +#endif // MICROPY_INCLUDED_STM32_LED_H diff --git a/ports/stm32/machine_i2c.c b/ports/stm32/machine_i2c.c index 1be2151e3..8fc6c2a1e 100644 --- a/ports/stm32/machine_i2c.c +++ b/ports/stm32/machine_i2c.c @@ -31,12 +31,13 @@ #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) +#if defined(STM32F4) // F4xx specific driver for I2C hardware peripheral // The hardware-specific I2C code below is based heavily on the code from @@ -86,7 +87,7 @@ STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp machine_hard_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "I2C(%u, freq=%u, timeout=%u)", self - &machine_hard_i2c_obj[0] + 1, - i2c_get_baudrate(&self->pyb->i2c->Init), + i2c_get_baudrate(self->pyb->i2c), *self->timeout); } @@ -423,22 +424,22 @@ typedef mp_machine_soft_i2c_obj_t machine_hard_i2c_obj_t; STATIC machine_hard_i2c_obj_t machine_hard_i2c_obj[] = { #if defined(MICROPY_HW_I2C1_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C1_SCL, &MICROPY_HW_I2C1_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C1_SCL, MICROPY_HW_I2C1_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C2_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C2_SCL, &MICROPY_HW_I2C2_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C2_SCL, MICROPY_HW_I2C2_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C3_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C3_SCL, &MICROPY_HW_I2C3_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C3_SCL, MICROPY_HW_I2C3_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C4_SCL) - {{&machine_hard_i2c_type}, 1, 500, &MICROPY_HW_I2C4_SCL, &MICROPY_HW_I2C4_SDA}, + {{&machine_hard_i2c_type}, 1, 500, MICROPY_HW_I2C4_SCL, MICROPY_HW_I2C4_SDA}, #else {{NULL}, 0, 0, NULL, NULL}, #endif @@ -548,3 +549,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 9a83f9f36..fb3e843bb 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -263,7 +263,7 @@ MP_NOINLINE STATIC bool init_flash_fs(uint reset_mode) { } #if MICROPY_HW_HAS_SDCARD -STATIC bool init_sdcard_fs(bool first_soft_reset) { +STATIC bool init_sdcard_fs(void) { bool first_part = true; for (int part_num = 1; part_num <= 4; ++part_num) { // create vfs object @@ -308,14 +308,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,6 +338,7 @@ 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 (switch_get()) { @@ -412,8 +413,9 @@ STATIC uint update_reset_mode(uint reset_mode) { #endif return reset_mode; } +#endif -int main(void) { +void stm32_main(uint32_t reset_mode) { // TODO disable JTAG /* STM32F4xx HAL library initialization: @@ -428,12 +430,12 @@ int main(void) { SystemClock_Config(); // enable GPIO clocks - __GPIOA_CLK_ENABLE(); - __GPIOB_CLK_ENABLE(); - __GPIOC_CLK_ENABLE(); - __GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(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 +444,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,20 +462,24 @@ 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_HW_ENABLE_HW_I2C + i2c_init0(); + #endif + #if MICROPY_HW_HAS_SDCARD + sdcard_init(); + #endif + storage_init(); soft_reset: - // check if user switch held to select the reset mode #if defined(MICROPY_HW_LED2) led_state(1, 0); led_state(2, 1); @@ -477,25 +489,11 @@ soft_reset: #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 @@ -552,13 +550,9 @@ soft_reset: can_init0(); #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. @@ -570,11 +564,18 @@ soft_reset: if (sdcard_is_present()) { // if there is a file in the flash called "SKIPSD", then we don't mount the SD card if (!mounted_flash || f_stat(&fs_user_mount_flash.fatfs, "/SKIPSD", NULL) != FR_OK) { - mounted_sdcard = init_sdcard_fs(first_soft_reset); + mounted_sdcard = init_sdcard_fs(); } } #endif + #if 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) { mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd)); @@ -619,12 +620,12 @@ soft_reset: // or whose initialisation can be safely deferred until after running // boot.py. -#if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB // init USB device to default setting if it was not already configured if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) { pyb_usb_dev_init(USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, NULL); } -#endif + #endif #if MICROPY_HW_HAS_MMA7660 // MMA accel: init and reset @@ -694,11 +695,11 @@ soft_reset_exit: #if MICROPY_HW_ENABLE_CAN can_deinit(); #endif + machine_deinit(); #if MICROPY_PY_THREAD pyb_thread_deinit(); #endif - first_soft_reset = false; goto soft_reset; } diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 8c59758fa..02a6f2a4b 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,33 @@ 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 || state & RCC_SR_BORRSTF) { reset_cause = PYB_RESET_POWER_ON; - } else if (state & RCC_CSR_PINRSTF) { + } else if (state & RCC_SR_PINRSTF) { reset_cause = PYB_RESET_HARD; } else { // default is soft reset @@ -96,7 +120,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]) @@ -199,7 +228,9 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); // Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t machine_bootloader(void) { + #if MICROPY_HW_ENABLE_USB pyb_usb_dev_deinit(); + #endif storage_flush(); HAL_RCC_DeInit(); @@ -210,7 +241,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 +249,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. @@ -265,7 +296,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { // set mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000; - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) mp_raise_NotImplementedError("machine.freq set not supported yet"); #endif @@ -359,33 +390,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 @@ -411,7 +459,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 4, machine_freq); STATIC mp_obj_t machine_sleep(void) { - #if defined(MCU_SERIES_L4) + #if defined(STM32L4) // Enter Stop 1 mode __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); @@ -443,7 +491,7 @@ STATIC mp_obj_t machine_sleep(void) { // takes longer to wake but reduces stop current HAL_PWREx_EnableFlashPowerDown(); - # if defined(MCU_SERIES_F7) + # if defined(STM32F7) HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI); # else HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); @@ -463,7 +511,11 @@ STATIC mp_obj_t machine_sleep(void) { // select PLL as system clock source MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK); + #if defined(STM32H7) + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) { + #else while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) { + #endif } #endif @@ -475,7 +527,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); STATIC mp_obj_t machine_deepsleep(void) { rtc_init_finalise(); -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) printf("machine.deepsleep not supported yet\n"); #else // We need to clear the PWR wake-up-flag before entering standby, since @@ -497,11 +549,13 @@ STATIC mp_obj_t machine_deepsleep(void) { // clear RTC wake-up flags RTC->ISR &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF); - #if defined(MCU_SERIES_F7) + #if defined(STM32F7) // disable wake-up flags PWR->CSR2 &= ~(PWR_CSR2_EWUP6 | PWR_CSR2_EWUP5 | PWR_CSR2_EWUP4 | PWR_CSR2_EWUP3 | PWR_CSR2_EWUP2 | PWR_CSR2_EWUP1); // clear global wake-up flag 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 +612,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 77668695f..88fe23692 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.h b/ports/stm32/modnetwork.h index ecda94da4..6796b087a 100644 --- a/ports/stm32/modnetwork.h +++ b/ports/stm32/modnetwork.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_MODNETWORK_H -#define MICROPY_INCLUDED_STMHAL_MODNETWORK_H +#ifndef MICROPY_INCLUDED_STM32_MODNETWORK_H +#define MICROPY_INCLUDED_STM32_MODNETWORK_H #define MOD_NETWORK_IPADDR_BUF_SIZE (4) @@ -80,4 +80,4 @@ void mod_network_init(void); void mod_network_register_nic(mp_obj_t nic); mp_obj_t mod_network_find_nic(const uint8_t *ip); -#endif // MICROPY_INCLUDED_STMHAL_MODNETWORK_H +#endif // MICROPY_INCLUDED_STM32_MODNETWORK_H diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c index 4f1af7354..8723994f4 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]) diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c index 763137c70..017bd42f8 100644 --- a/ports/stm32/modnwwiznet5k.c +++ b/ports/stm32/modnwwiznet5k.c @@ -36,7 +36,6 @@ #include "lib/netutils/netutils.h" #include "modnetwork.h" #include "pin.h" -#include "genhdr/pins.h" #include "spi.h" #include "ethernet/wizchip_conf.h" @@ -48,7 +47,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 +72,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 +344,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); diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 81cbdcc19..c7f2844a4 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -34,6 +34,7 @@ #include "lib/utils/pyexec.h" #include "lib/oofatfs/ff.h" #include "lib/oofatfs/diskio.h" +#include "drivers/dht/dht.h" #include "gccollect.h" #include "stm32_it.h" #include "irq.h" @@ -150,6 +151,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) }, { MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&pyb_repl_uart_obj) }, + #if MICROPY_HW_ENABLE_USB { MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) }, { MP_ROM_QSTR(MP_QSTR_hid_mouse), MP_ROM_PTR(&pyb_usb_hid_mouse_obj) }, { MP_ROM_QSTR(MP_QSTR_hid_keyboard), MP_ROM_PTR(&pyb_usb_hid_keyboard_obj) }, @@ -158,6 +160,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { // these 2 are deprecated; use USB_VCP.isconnected and USB_HID.send instead { MP_ROM_QSTR(MP_QSTR_have_cdc), MP_ROM_PTR(&pyb_have_cdc_obj) }, { MP_ROM_QSTR(MP_QSTR_hid), MP_ROM_PTR(&pyb_hid_send_report_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_millis), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_elapsed_millis), MP_ROM_PTR(&pyb_elapsed_millis_obj) }, @@ -168,6 +171,9 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) }, { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + // This function is not intended to be public and may be moved elsewhere + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) }, #if MICROPY_HW_ENABLE_RNG @@ -203,15 +209,19 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { #if defined(MICROPY_HW_LED1) { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pyb_led_type) }, #endif + #if MICROPY_HW_ENABLE_HW_I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) }, + #endif { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, #if MICROPY_HW_ENABLE_CAN { 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/modules/dht.py b/ports/stm32/modules/dht.py new file mode 120000 index 000000000..2aa2f5cbf --- /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/modutime.c b/ports/stm32/modutime.c index 54045f4c5..6b5c84115 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 000000000..d4b812331 --- /dev/null +++ b/ports/stm32/mpconfigboard_common.h @@ -0,0 +1,175 @@ +/* + * 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 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 the CAN peripheral, exposed as pyb.CAN +#ifndef MICROPY_HW_ENABLE_CAN +#define MICROPY_HW_ENABLE_CAN (0) +#endif + +// Whether to enable USB support +#ifndef MICROPY_HW_ENABLE_USB +#define MICROPY_HW_ENABLE_USB (0) +#endif + +// Whether to enable the PA0-PA3 servo driver, exposed as pyb.Servo +#ifndef MICROPY_HW_ENABLE_SERVO +#define MICROPY_HW_ENABLE_SERVO (0) +#endif + +// Whether to enable a USR switch, exposed as pyb.Switch +#ifndef MICROPY_HW_HAS_SWITCH +#define MICROPY_HW_HAS_SWITCH (0) +#endif + +// Whether to expose internal flash storage as pyb.Flash +#ifndef MICROPY_HW_HAS_FLASH +#define MICROPY_HW_HAS_FLASH (0) +#endif + +// Whether to enable the SD card interface, exposed as pyb.SDCard +#ifndef MICROPY_HW_HAS_SDCARD +#define MICROPY_HW_HAS_SDCARD (0) +#endif + +// Whether to enable the MMA7660 driver, exposed as pyb.Accel +#ifndef MICROPY_HW_HAS_MMA7660 +#define MICROPY_HW_HAS_MMA7660 (0) +#endif + +// Whether to enable the LCD32MK driver, exposed as pyb.LCD +#ifndef MICROPY_HW_HAS_LCD +#define MICROPY_HW_HAS_LCD (0) +#endif + +/*****************************************************************************/ +// General configuration + +// Configuration for STM32F4 series +#if defined(STM32F4) + +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_TIMER (14) +#define MICROPY_HW_MAX_UART (6) + +// Configuration for STM32F7 series +#elif defined(STM32F7) + +#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx) +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff07a10) +#else +#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ff0f420) +#endif + +#define PYB_EXTI_NUM_VECTORS (24) +#define MICROPY_HW_MAX_TIMER (17) +#define MICROPY_HW_MAX_UART (8) + +// Configuration for 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 + +#if MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE +// Provide block device macros if internal flash storage is enabled +#define MICROPY_HW_BDEV_IOCTL flash_bdev_ioctl +#define MICROPY_HW_BDEV_READBLOCK flash_bdev_readblock +#define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock +#endif + +// Enable hardware I2C if there are any peripherals defined +#if defined(MICROPY_HW_I2C1_SCL) || defined(MICROPY_HW_I2C2_SCL) \ + || defined(MICROPY_HW_I2C3_SCL) || defined(MICROPY_HW_I2C4_SCL) +#define MICROPY_HW_ENABLE_HW_I2C (1) +#else +#define MICROPY_HW_ENABLE_HW_I2C (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 51d442561..a0a67e95f 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) @@ -96,6 +97,7 @@ #define MICROPY_PY_BUILTINS_HELP_MODULES (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) #define MICROPY_PY_CMATH (1) @@ -131,13 +133,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) @@ -231,20 +235,6 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_ROM_QSTR(MP_QSTR_pyb), MP_ROM_PTR(&pyb_module) }, \ { MP_ROM_QSTR(MP_QSTR_stm), MP_ROM_PTR(&stm_module) }, \ -#if defined(MCU_SERIES_F7) -#define PYB_EXTI_NUM_VECTORS (24) -#define MICROPY_HW_MAX_TIMER (17) -#define MICROPY_HW_MAX_UART (8) -#elif defined(MCU_SERIES_L4) -#define PYB_EXTI_NUM_VECTORS (23) -#define MICROPY_HW_MAX_TIMER (17) -#define MICROPY_HW_MAX_UART (6) -#else -#define PYB_EXTI_NUM_VECTORS (23) -#define MICROPY_HW_MAX_TIMER (14) -#define MICROPY_HW_MAX_UART (6) -#endif - #define MP_STATE_PORT MP_STATE_VM #define MICROPY_PORT_ROOT_POINTERS \ @@ -299,8 +289,6 @@ typedef long mp_off_t; // value from disable_irq back to enable_irq. If you really need // to know the machine-specific values, see irq.h. -#include STM32_HAL_H - static inline void enable_irq(mp_uint_t state) { __set_PRIMASK(state); } @@ -351,12 +339,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 e9c4f28f7..0108d9026 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); } @@ -85,7 +88,7 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { } void mp_hal_ticks_cpu_enable(void) { - if (!mp_hal_ticks_cpu_enabled) { + if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; #if defined(__CORTEX_M) && __CORTEX_M == 7 // on Cortex-M7 we must unlock the DWT before writing to its registers @@ -93,59 +96,58 @@ void mp_hal_ticks_cpu_enable(void) { #endif DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - mp_hal_ticks_cpu_enabled = true; } } void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { if (0) { - #ifdef __GPIOA_CLK_ENABLE + #ifdef __HAL_RCC_GPIOA_CLK_ENABLE } else if (gpio == GPIOA) { - __GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); #endif - #ifdef __GPIOB_CLK_ENABLE + #ifdef __HAL_RCC_GPIOB_CLK_ENABLE } else if (gpio == GPIOB) { - __GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); #endif - #ifdef __GPIOC_CLK_ENABLE + #ifdef __HAL_RCC_GPIOC_CLK_ENABLE } else if (gpio == GPIOC) { - __GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); #endif - #ifdef __GPIOD_CLK_ENABLE + #ifdef __HAL_RCC_GPIOD_CLK_ENABLE } else if (gpio == GPIOD) { - __GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); #endif - #ifdef __GPIOE_CLK_ENABLE + #ifdef __HAL_RCC_GPIOE_CLK_ENABLE } else if (gpio == GPIOE) { - __GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); #endif - #if defined(GPIOF) && defined(__GPIOF_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOF_CLK_ENABLE } else if (gpio == GPIOF) { - __GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); #endif - #if defined(GPIOG) && defined(__GPIOG_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOG_CLK_ENABLE } else if (gpio == GPIOG) { #if defined(STM32L476xx) || defined(STM32L486xx) // Port G pins 2 thru 15 are powered using VddIO2 on these MCUs. HAL_PWREx_EnableVddIO2(); #endif - __GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); #endif - #ifdef __GPIOH_CLK_ENABLE + #ifdef __HAL_RCC_GPIOH_CLK_ENABLE } else if (gpio == GPIOH) { - __GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); #endif - #if defined(GPIOI) && defined(__GPIOI_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOI_CLK_ENABLE } else if (gpio == GPIOI) { - __GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); #endif - #if defined(GPIOJ) && defined(__GPIOJ_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOJ_CLK_ENABLE } else if (gpio == GPIOJ) { - __GPIOJ_CLK_ENABLE(); + __HAL_RCC_GPIOJ_CLK_ENABLE(); #endif - #if defined(GPIOK) && defined(__GPIOK_CLK_ENABLE) + #ifdef __HAL_RCC_GPIOK_CLK_ENABLE } else if (gpio == GPIOK) { - __GPIOK_CLK_ENABLE(); + __HAL_RCC_GPIOK_CLK_ENABLE(); #endif } } diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 939df0b3d..2843a79cd 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); @@ -33,10 +15,9 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable #define mp_hal_quiet_timing_exit(irq_state) restore_irq_pri(irq_state) #define mp_hal_delay_us_fast(us) mp_hal_delay_us(us) -extern bool mp_hal_ticks_cpu_enabled; void mp_hal_ticks_cpu_enable(void); static inline mp_uint_t mp_hal_ticks_cpu(void) { - if (!mp_hal_ticks_cpu_enabled) { + if (!(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)) { mp_hal_ticks_cpu_enable(); } return DWT->CYCCNT; @@ -63,8 +44,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) diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index 6a9eb0d79..0d9fde687 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 ee2d84646..fbd3f00c1 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 90de79e5c..b0e05256f 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 @@ -63,6 +63,9 @@ typedef struct { extern const mp_obj_type_t pin_type; extern const mp_obj_type_t pin_af_type; +// Include all of the individual pin objects +#include "genhdr/pins.h" + typedef struct { const char *name; const pin_obj_t *pin; @@ -97,4 +100,4 @@ const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit); const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx); const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name); -#endif // MICROPY_INCLUDED_STMHAL_PIN_H +#endif // MICROPY_INCLUDED_STM32_PIN_H diff --git a/ports/stm32/portmodules.h b/ports/stm32/portmodules.h index b575109b8..81cb7fd04 100644 --- a/ports/stm32/portmodules.h +++ b/ports/stm32/portmodules.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_PORTMODULES_H -#define MICROPY_INCLUDED_STMHAL_PORTMODULES_H +#ifndef MICROPY_INCLUDED_STM32_PORTMODULES_H +#define MICROPY_INCLUDED_STM32_PORTMODULES_H extern const mp_obj_module_t pyb_module; extern const mp_obj_module_t stm_module; @@ -40,4 +40,4 @@ MP_DECLARE_CONST_FUN_OBJ_1(time_sleep_us_obj); MP_DECLARE_CONST_FUN_OBJ_0(mod_os_sync_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj); -#endif // MICROPY_INCLUDED_STMHAL_PORTMODULES_H +#endif // MICROPY_INCLUDED_STM32_PORTMODULES_H diff --git a/ports/stm32/pybthread.h b/ports/stm32/pybthread.h index f628f934b..42300508c 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 000000000..97f055c09 --- /dev/null +++ b/ports/stm32/qspi.c @@ -0,0 +1,276 @@ +/* + * 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 + while (len) { + while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + } + // TODO it seems that writes need to be 32-bit wide to start the xfer... + //*(volatile uint8_t*)QUADSPI->DR = *src++; + //--len; + QUADSPI->DR = *(uint32_t*)src; + src += 4; + len -= 4; + } + } + + // Wait for write to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +STATIC uint32_t qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { + (void)self_in; + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + QUADSPI->DLR = len - 1; // number of bytes to read + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode + | 1 << QUADSPI_CCR_DMODE_Pos // data on 1 line + | 0 << QUADSPI_CCR_DCYC_Pos // 0 dummy cycles + | 0 << QUADSPI_CCR_ABMODE_Pos // no alternate byte + | 0 << QUADSPI_CCR_ADMODE_Pos // no address + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // read opcode + ; + + // Wait for read to finish + while (!(QUADSPI->SR & QUADSPI_SR_TCF)) { + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + // Read result + return QUADSPI->DR; +} + +STATIC void qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { + (void)self_in; + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag + + QUADSPI->DLR = len - 1; // number of bytes to read + + QUADSPI->CCR = + 0 << QUADSPI_CCR_DDRM_Pos // DDR mode disabled + | 0 << QUADSPI_CCR_SIOO_Pos // send instruction every transaction + | 1 << QUADSPI_CCR_FMODE_Pos // indirect read mode + | 3 << QUADSPI_CCR_DMODE_Pos // data on 4 lines + | 4 << QUADSPI_CCR_DCYC_Pos // 4 dummy cycles + | 0 << QUADSPI_CCR_ABSIZE_Pos // 8-bit alternate byte + | 3 << QUADSPI_CCR_ABMODE_Pos // alternate byte on 4 lines + | 2 << QUADSPI_CCR_ADSIZE_Pos // 24-bit address size + | 3 << QUADSPI_CCR_ADMODE_Pos // address on 4 lines + | 1 << QUADSPI_CCR_IMODE_Pos // instruction on 1 line + | cmd << QUADSPI_CCR_INSTRUCTION_Pos // quad read opcode + ; + + QUADSPI->ABR = 0; // alternate byte: disable continuous read mode + QUADSPI->AR = addr; // addres to read from + + // Read in the data + while (len) { + while (!(QUADSPI->SR & QUADSPI_SR_FTF)) { + } + *(uint32_t*)dest = QUADSPI->DR; + dest += 4; + len -= 4; + } + + QUADSPI->FCR = QUADSPI_FCR_CTCF; // clear TC flag +} + +const mp_qspi_proto_t qspi_proto = { + .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 000000000..c774b1258 --- /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 000000000..7f0973346 --- /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/rng.c b/ports/stm32/rng.c index c0c5e9aeb..85dcc1410 100644 --- a/ports/stm32/rng.c +++ b/ports/stm32/rng.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2018 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,44 +24,35 @@ * THE SOFTWARE. */ -#include - -#include "py/obj.h" #include "rng.h" #if MICROPY_HW_ENABLE_RNG -/// \moduleref pyb - -STATIC RNG_HandleTypeDef RNGHandle = {.Instance = NULL}; - -void rng_init0(void) { - // reset the RNG handle - memset(&RNGHandle, 0, sizeof(RNG_HandleTypeDef)); - RNGHandle.Instance = RNG; -} - -void rng_init(void) { - __RNG_CLK_ENABLE(); - HAL_RNG_Init(&RNGHandle); -} +#define RNG_TIMEOUT_MS (10) uint32_t rng_get(void) { - if (RNGHandle.State == HAL_RNG_STATE_RESET) { - rng_init(); + // Enable the RNG peripheral if it's not already enabled + if (!(RNG->CR & RNG_CR_RNGEN)) { + __HAL_RCC_RNG_CLK_ENABLE(); + RNG->CR |= RNG_CR_RNGEN; } - return HAL_RNG_GetRandomNumber(&RNGHandle); + + // Wait for a new random number to be ready, takes on the order of 10us + uint32_t start = HAL_GetTick(); + while (!(RNG->SR & RNG_SR_DRDY)) { + if (HAL_GetTick() - start >= RNG_TIMEOUT_MS) { + return 0; + } + } + + // Get and return the new random number + return RNG->DR; } -/// \function rng() -/// Return a 30-bit hardware generated random number. +// Return a 30-bit hardware generated random number. STATIC mp_obj_t pyb_rng_get(void) { - if (RNGHandle.State == HAL_RNG_STATE_RESET) { - rng_init(); - } - return mp_obj_new_int(HAL_RNG_GetRandomNumber(&RNGHandle) >> 2); + return mp_obj_new_int(rng_get() >> 2); } - MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get); #endif // MICROPY_HW_ENABLE_RNG diff --git a/ports/stm32/rng.h b/ports/stm32/rng.h index 43e49fe72..ed9cc80f2 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 73272d363..8fb6ae29f 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,7 +523,7 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { date.Month = mp_obj_get_int(items[1]); date.Date = mp_obj_get_int(items[2]); date.WeekDay = mp_obj_get_int(items[3]); - HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN); + HAL_RTC_SetDate(&RTCHandle, &date, RTC_FORMAT_BIN); RTC_TimeTypeDef time; time.Hours = mp_obj_get_int(items[4]); @@ -521,7 +533,7 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { time.TimeFormat = RTC_HOURFORMAT12_AM; time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; time.StoreOperation = RTC_STOREOPERATION_SET; - HAL_RTC_SetTime(&RTCHandle, &time, FORMAT_BIN); + HAL_RTC_SetTime(&RTCHandle, &time, RTC_FORMAT_BIN); return mp_const_none; } @@ -623,9 +635,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,8 +648,10 @@ 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 @@ -651,8 +668,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 09ab2aedf..307f8885e 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 484426b84..9244be5d4 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,31 +141,37 @@ 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); HAL_NVIC_EnableIRQ(SDMMC_IRQn); @@ -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 { diff --git a/ports/stm32/sdcard.h b/ports/stm32/sdcard.h index 8c698fc2f..4afc258aa 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 0e54b4d0a..966d2c688 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 } diff --git a/ports/stm32/servo.h b/ports/stm32/servo.h index c602a07da..0160568af 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 cfd9c2667..a6e714317 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,8 +194,9 @@ STATIC int spi_find(mp_obj_t id) { // sets the parameters in the SPI_InitTypeDef struct // if an argument is -1 then the corresponding parameter is not changed -STATIC void spi_set_params(SPI_HandleTypeDef *spi, uint32_t prescale, int32_t baudrate, +STATIC void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baudrate, int32_t polarity, int32_t phase, int32_t bits, int32_t firstbit) { + SPI_HandleTypeDef *spi = spi_obj->spi; SPI_InitTypeDef *init = &spi->Init; if (prescale != 0xffffffff || baudrate != -1) { @@ -241,83 +240,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 +331,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,54 +354,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). +STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t timeout) { uint32_t start = HAL_GetTick(); - while (HAL_SPI_GetState(spi) != HAL_SPI_STATE_READY) { + 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() - start >= timeout) { return HAL_TIMEOUT; } @@ -407,7 +421,7 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t // and use that value for the baudrate in the formula, plus a small constant. #define SPI_TRANSFER_TIMEOUT(len) ((len) + 100) -STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) { +STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint8_t *dest, uint32_t timeout) { // Note: there seems to be a problem sending 1 byte using DMA the first // time directly after the SPI/DMA is initialised. The cause of this is // unknown but we sidestep the issue by using polling for 1 byte transfer. @@ -426,7 +440,7 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s MP_HAL_CLEAN_DCACHE(src, len); status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, len); if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, timeout); + status = spi_wait_dma_finished(self, timeout); } dma_deinit(self->tx_dma_descr); } @@ -448,7 +462,7 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); status = HAL_SPI_Receive_DMA(self->spi, dest, len); if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, timeout); + status = spi_wait_dma_finished(self, timeout); } if (self->spi->hdmatx != NULL) { dma_deinit(self->tx_dma_descr); @@ -469,7 +483,7 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s MP_HAL_CLEANINVALIDATE_DCACHE(dest, len); status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, len); if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, timeout); + status = spi_wait_dma_finished(self, timeout); } dma_deinit(self->tx_dma_descr); dma_deinit(self->rx_dma_descr); @@ -481,7 +495,9 @@ STATIC void spi_transfer(const pyb_spi_obj_t *self, size_t len, const uint8_t *s } } -STATIC void spi_print(const mp_print_t *print, SPI_HandleTypeDef *spi, bool legacy) { +STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy) { + SPI_HandleTypeDef *spi = spi_obj->spi; + uint spi_num = 1; // default to SPI1 if (spi->Instance == SPI2) { spi_num = 2; } else if (spi->Instance == SPI3) { spi_num = 3; } @@ -520,7 +536,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 +546,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 +591,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 +599,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 +689,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 +723,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 +793,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 +841,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 +863,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 +908,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 +944,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 +976,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 eda109a7e..41f91b289 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 000000000..91ec4df5e --- /dev/null +++ b/ports/stm32/spibdev.c @@ -0,0 +1,81 @@ +/* + * 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" + +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_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_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_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_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; +} diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index f1ac9b6b8..987ace69a 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -143,9 +143,11 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) { NVIC_SystemReset(); } + #if MICROPY_HW_ENABLE_USB // We need to disable the USB so it doesn't try to write data out on // the VCP and then block indefinitely waiting for the buffer to drain. pyb_usb_flags = 0; + #endif mp_hal_stdout_tx_str("HardFault\r\n"); @@ -337,14 +339,14 @@ void SysTick_Handler(void) { * @param None * @retval None */ -#if defined(USE_USB_FS) +#if MICROPY_HW_USB_FS void OTG_FS_IRQHandler(void) { IRQ_ENTER(OTG_FS_IRQn); HAL_PCD_IRQHandler(&pcd_fs_handle); IRQ_EXIT(OTG_FS_IRQn); } #endif -#if defined(USE_USB_HS) +#if MICROPY_HW_USB_HS void OTG_HS_IRQHandler(void) { IRQ_ENTER(OTG_HS_IRQn); HAL_PCD_IRQHandler(&pcd_hs_handle); @@ -352,7 +354,7 @@ void OTG_HS_IRQHandler(void) { } #endif -#if defined(USE_USB_FS) || defined(USE_USB_HS) +#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS /** * @brief This function handles USB OTG Common FS/HS Wakeup functions. * @param *pcd_handle for FS or HS @@ -383,8 +385,13 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) { /* Select PLL as SYSCLK */ MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK); + #if defined(STM32H7) + while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) + {} + #else while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) {} + #endif /* ungate PHY clock */ __HAL_PCD_UNGATE_PHYCLOCK(pcd_handle); @@ -393,7 +400,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 +418,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 @@ -515,7 +522,7 @@ void PVD_IRQHandler(void) { IRQ_EXIT(PVD_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void PVD_PVM_IRQHandler(void) { IRQ_ENTER(PVD_PVM_IRQn); Handle_EXTI_Irq(EXTI_PVD_OUTPUT); @@ -556,7 +563,7 @@ void TIM1_BRK_TIM9_IRQHandler(void) { IRQ_EXIT(TIM1_BRK_TIM9_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM1_BRK_TIM15_IRQHandler(void) { IRQ_ENTER(TIM1_BRK_TIM15_IRQn); timer_irq_handler(15); @@ -571,7 +578,7 @@ void TIM1_UP_TIM10_IRQHandler(void) { IRQ_EXIT(TIM1_UP_TIM10_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM1_UP_TIM16_IRQHandler(void) { IRQ_ENTER(TIM1_UP_TIM16_IRQn); timer_irq_handler(1); @@ -586,7 +593,7 @@ void TIM1_TRG_COM_TIM11_IRQHandler(void) { IRQ_EXIT(TIM1_TRG_COM_TIM11_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM1_TRG_COM_TIM17_IRQHandler(void) { IRQ_ENTER(TIM1_TRG_COM_TIM17_IRQn); timer_irq_handler(17); @@ -655,7 +662,7 @@ void TIM8_UP_TIM13_IRQHandler(void) { IRQ_EXIT(TIM8_UP_TIM13_IRQn); } -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) void TIM8_UP_IRQHandler(void) { IRQ_ENTER(TIM8_UP_IRQn); timer_irq_handler(8); @@ -742,6 +749,12 @@ void CAN1_RX1_IRQHandler(void) { IRQ_EXIT(CAN1_RX1_IRQn); } +void CAN1_SCE_IRQHandler(void) { + IRQ_ENTER(CAN1_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_1); + IRQ_EXIT(CAN1_SCE_IRQn); +} + void CAN2_RX0_IRQHandler(void) { IRQ_ENTER(CAN2_RX0_IRQn); can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0); @@ -753,6 +766,12 @@ void CAN2_RX1_IRQHandler(void) { can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1); IRQ_EXIT(CAN2_RX1_IRQn); } + +void CAN2_SCE_IRQHandler(void) { + IRQ_ENTER(CAN2_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_2); + IRQ_EXIT(CAN2_SCE_IRQn); +} #endif // MICROPY_HW_ENABLE_CAN #if defined(MICROPY_HW_I2C1_SCL) diff --git a/ports/stm32/stm32_it.h b/ports/stm32/stm32_it.h index b498dee8d..46523e567 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 4b329c2db..1450f2156 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,37 @@ #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 - #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). + HAL_NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH, IRQ_SUBPRI_FLASH); + HAL_NVIC_EnableIRQ(FLASH_IRQn); + } } uint32_t storage_get_block_size(void) { @@ -219,59 +65,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 +122,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 +131,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 +145,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 +159,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 +190,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 diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h index 291e09a9a..7250b6dbf 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 b71a03181..251902259 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 @@ -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,28 +371,46 @@ 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.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) + #elif defined(STM32L4) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; @@ -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(); @@ -486,7 +604,7 @@ void SystemClock_Config(void) } void HAL_MspInit(void) { -#if defined(MCU_SERIES_F7) +#if defined(STM32F7) || defined(STM32H7) /* Enable I-Cache */ SCB_EnableICache(); diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h index c1def50c2..256a500c2 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 96a6baa02..18661da9c 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -162,11 +162,12 @@ 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); @@ -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 @@ -227,16 +229,22 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { // respective APB clock. See DM00031020 Rev 4, page 115. uint32_t timer_get_source_freq(uint32_t tim_id) { uint32_t source; + uint32_t latency; + RCC_ClkInitTypeDef rcc_init; + + // Get clock config. + HAL_RCC_GetClockConfig(&rcc_init, &latency); + if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) { // TIM{1,8,9,10,11} are on APB2 source = HAL_RCC_GetPCLK2Freq(); - if ((uint32_t)((RCC->CFGR & RCC_CFGR_PPRE2) >> 3) != RCC_HCLK_DIV1) { + if (rcc_init.APB2CLKDivider != RCC_HCLK_DIV1) { source *= 2; } } else { // TIM{2,3,4,5,6,7,12,13,14} are on APB1 source = HAL_RCC_GetPCLK1Freq(); - if ((uint32_t)(RCC->CFGR & RCC_CFGR_PPRE1) != RCC_HCLK_DIV1) { + if (rcc_init.APB1CLKDivider != RCC_HCLK_DIV1) { source *= 2; } } @@ -302,7 +310,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 +447,7 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ mp_printf(print, "Timer(%u)", self->tim_id); } else { uint32_t prescaler = self->tim.Instance->PSC & 0xffff; - uint32_t period = __HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self); + uint32_t period = __HAL_TIM_GET_AUTORELOAD(&self->tim) & TIMER_CNT_MASK(self); // for efficiency, we compute and print freq as an int (not a float) uint32_t freq = timer_get_source_freq(self->tim_id) / ((prescaler + 1) * (period + 1)); mp_printf(print, "Timer(%u, freq=%u, prescaler=%u, period=%u, mode=%s, div=%u", @@ -554,46 +562,50 @@ 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 } @@ -639,15 +651,19 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons // It assumes that timer instance pointer has the lower 8 bits cleared. #define TIM_ENTRY(id, irq) [id - 1] = (uint32_t)TIM##id | irq STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) TIM_ENTRY(1, TIM1_UP_TIM10_IRQn), - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) TIM_ENTRY(1, TIM1_UP_TIM16_IRQn), #endif TIM_ENTRY(2, TIM2_IRQn), 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 +671,9 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { TIM_ENTRY(7, TIM7_IRQn), #endif #if defined(TIM8) - #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #if defined(STM32F4) || defined(STM32F7) TIM_ENTRY(8, TIM8_UP_TIM13_IRQn), - #elif defined(MCU_SERIES_L4) + #elif defined(STM32L4) TIM_ENTRY(8, TIM8_UP_IRQn), #endif #endif @@ -680,14 +696,26 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { TIM_ENTRY(14, TIM8_TRG_COM_TIM14_IRQn), #endif #if defined(TIM15) + #if defined(STM32H7) + TIM_ENTRY(15, TIM15_IRQn), + #else TIM_ENTRY(15, TIM1_BRK_TIM15_IRQn), #endif + #endif #if defined(TIM16) + #if defined(STM32H7) + TIM_ENTRY(16, TIM16_IRQn), + #else TIM_ENTRY(16, TIM1_UP_TIM16_IRQn), #endif + #endif #if defined(TIM17) + #if defined(STM32H7) + TIM_ENTRY(17, TIM17_IRQn), + #else TIM_ENTRY(17, TIM1_TRG_COM_TIM17_IRQn), #endif + #endif }; #undef TIM_ENTRY @@ -1049,8 +1077,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 +1094,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 +1120,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 +1142,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 +1158,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 +1185,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 +1297,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 +1317,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 +1397,7 @@ STATIC void timer_handle_irq_channel(pyb_timer_obj_t *tim, uint8_t channel, mp_o uint32_t irq_mask = TIMER_IRQ_MASK(channel); if (__HAL_TIM_GET_FLAG(&tim->tim, irq_mask) != RESET) { - if (__HAL_TIM_GET_ITSTATUS(&tim->tim, irq_mask) != RESET) { + if (__HAL_TIM_GET_IT_SOURCE(&tim->tim, irq_mask) != RESET) { // clear the interrupt __HAL_TIM_CLEAR_IT(&tim->tim, irq_mask); diff --git a/ports/stm32/timer.h b/ports/stm32/timer.h index 775accc3d..2ba91cf15 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 0b46d4f04..a8b5d7dca 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -34,7 +34,6 @@ #include "py/mphal.h" #include "uart.h" #include "irq.h" -#include "genhdr/pins.h" /// \moduleref pyb /// \class UART - duplex serial communication bus @@ -91,8 +90,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; } @@ -164,9 +181,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 @@ -175,19 +192,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 @@ -196,19 +213,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 @@ -217,9 +234,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 @@ -228,9 +245,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 @@ -239,9 +256,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 @@ -250,9 +277,9 @@ 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 @@ -261,9 +288,9 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) { uart_unit = 8; UARTx = UART8; irqn = UART8_IRQn; - pins[0] = &MICROPY_HW_UART8_TX; - pins[1] = &MICROPY_HW_UART8_RX; - __UART8_CLK_ENABLE(); + pins[0] = MICROPY_HW_UART8_TX; + pins[1] = MICROPY_HW_UART8_RX; + __HAL_RCC_UART8_CLK_ENABLE(); break; #endif @@ -355,7 +382,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(STM32F7) || defined(STM32L4) || defined(STM32H7) return self->uart.Instance->RDR & self->char_mask; #else return self->uart.Instance->DR & self->char_mask; @@ -434,7 +461,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; @@ -473,7 +500,7 @@ void uart_irq_handler(mp_uint_t uart_id) { uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len; if (next_head != self->read_buf_tail) { // only read data if room in buf - #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) + #if defined(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 @@ -500,7 +527,14 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k if (!self->is_enabled) { mp_printf(print, "UART(%u)", self->uart_id); } else { - mp_int_t bits = (self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9); + mp_int_t bits; + switch (self->uart.Init.WordLength) { + #ifdef UART_WORDLENGTH_7B + case UART_WORDLENGTH_7B: bits = 7; break; + #endif + case UART_WORDLENGTH_8B: bits = 8; break; + case UART_WORDLENGTH_9B: default: bits = 9; break; + } if (self->uart.Init.Parity != UART_PARITY_NONE) { bits -= 1; } @@ -580,6 +614,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"); } @@ -647,15 +685,28 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const // compute actual baudrate that was configured // (this formula assumes UART_OVERSAMPLING_16) uint32_t actual_baudrate = 0; - #if defined(MCU_SERIES_F7) + #if defined(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 @@ -780,55 +831,55 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { HAL_UART_DeInit(uart); if (uart->Instance == USART1) { HAL_NVIC_DisableIRQ(USART1_IRQn); - __USART1_FORCE_RESET(); - __USART1_RELEASE_RESET(); - __USART1_CLK_DISABLE(); + __HAL_RCC_USART1_FORCE_RESET(); + __HAL_RCC_USART1_RELEASE_RESET(); + __HAL_RCC_USART1_CLK_DISABLE(); } else if (uart->Instance == USART2) { HAL_NVIC_DisableIRQ(USART2_IRQn); - __USART2_FORCE_RESET(); - __USART2_RELEASE_RESET(); - __USART2_CLK_DISABLE(); + __HAL_RCC_USART2_FORCE_RESET(); + __HAL_RCC_USART2_RELEASE_RESET(); + __HAL_RCC_USART2_CLK_DISABLE(); #if defined(USART3) } else if (uart->Instance == USART3) { HAL_NVIC_DisableIRQ(USART3_IRQn); - __USART3_FORCE_RESET(); - __USART3_RELEASE_RESET(); - __USART3_CLK_DISABLE(); + __HAL_RCC_USART3_FORCE_RESET(); + __HAL_RCC_USART3_RELEASE_RESET(); + __HAL_RCC_USART3_CLK_DISABLE(); #endif #if defined(UART4) } else if (uart->Instance == UART4) { HAL_NVIC_DisableIRQ(UART4_IRQn); - __UART4_FORCE_RESET(); - __UART4_RELEASE_RESET(); - __UART4_CLK_DISABLE(); + __HAL_RCC_UART4_FORCE_RESET(); + __HAL_RCC_UART4_RELEASE_RESET(); + __HAL_RCC_UART4_CLK_DISABLE(); #endif #if defined(UART5) } else if (uart->Instance == UART5) { HAL_NVIC_DisableIRQ(UART5_IRQn); - __UART5_FORCE_RESET(); - __UART5_RELEASE_RESET(); - __UART5_CLK_DISABLE(); + __HAL_RCC_UART5_FORCE_RESET(); + __HAL_RCC_UART5_RELEASE_RESET(); + __HAL_RCC_UART5_CLK_DISABLE(); #endif #if defined(UART6) } else if (uart->Instance == USART6) { HAL_NVIC_DisableIRQ(USART6_IRQn); - __USART6_FORCE_RESET(); - __USART6_RELEASE_RESET(); - __USART6_CLK_DISABLE(); + __HAL_RCC_USART6_FORCE_RESET(); + __HAL_RCC_USART6_RELEASE_RESET(); + __HAL_RCC_USART6_CLK_DISABLE(); #endif #if defined(UART7) } else if (uart->Instance == UART7) { HAL_NVIC_DisableIRQ(UART7_IRQn); - __UART7_FORCE_RESET(); - __UART7_RELEASE_RESET(); - __UART7_CLK_DISABLE(); + __HAL_RCC_UART7_FORCE_RESET(); + __HAL_RCC_UART7_RELEASE_RESET(); + __HAL_RCC_UART7_CLK_DISABLE(); #endif #if defined(UART8) } else if (uart->Instance == UART8) { HAL_NVIC_DisableIRQ(UART8_IRQn); - __UART8_FORCE_RESET(); - __UART8_RELEASE_RESET(); - __UART8_CLK_DISABLE(); + __HAL_RCC_UART8_FORCE_RESET(); + __HAL_RCC_UART8_RELEASE_RESET(); + __HAL_RCC_UART8_CLK_DISABLE(); #endif } return mp_const_none; @@ -885,7 +936,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(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 d176520a1..d06508e8e 100644 --- a/ports/stm32/uart.h +++ b/ports/stm32/uart.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_UART_H -#define MICROPY_INCLUDED_STMHAL_UART_H +#ifndef MICROPY_INCLUDED_STM32_UART_H +#define MICROPY_INCLUDED_STM32_UART_H typedef enum { PYB_UART_NONE = 0, @@ -49,4 +49,4 @@ mp_uint_t uart_rx_any(pyb_uart_obj_t *uart_obj); int uart_rx_char(pyb_uart_obj_t *uart_obj); void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); -#endif // MICROPY_INCLUDED_STMHAL_UART_H +#endif // MICROPY_INCLUDED_STM32_UART_H diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c index 69f381d9b..b0bdb3a08 100644 --- a/ports/stm32/usb.c +++ b/ports/stm32/usb.c @@ -42,12 +42,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 @@ -61,10 +66,8 @@ typedef struct _usb_device_t { usbd_hid_itf_t usbd_hid_itf; } usb_device_t; -#ifdef USE_DEVICE_MODE usb_device_t usb_device; pyb_usb_storage_medium_t pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_NONE; -#endif // predefined hid mouse data STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = { @@ -110,7 +113,8 @@ void pyb_usb_init0(void) { } bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info) { -#ifdef USE_DEVICE_MODE + bool high_speed = (mode & USBD_MODE_HIGH_SPEED) != 0; + mode &= 0x7f; usb_device_t *usb_dev = &usb_device; if (!usb_dev->enabled) { // only init USB once in the device's power-lifetime @@ -123,7 +127,7 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H // set up the USBD state USBD_HandleTypeDef *usbd = &usb_dev->hUSBDDevice; - usbd->id = USB_PHY_ID; + usbd->id = MICROPY_HW_USB_MAIN_DEV; usbd->dev_state = USBD_STATE_DEFAULT; usbd->pDesc = (USBD_DescriptorsTypeDef*)&USBD_Descriptors; usbd->pClass = &USBD_CDC_MSC_HID; @@ -144,11 +148,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; } @@ -170,11 +173,9 @@ int usb_vcp_recv_byte(uint8_t *c) { } void usb_vcp_send_strn(const char *str, int len) { -#ifdef USE_DEVICE_MODE if (usb_device.enabled) { usbd_cdc_tx_always(&usb_device.usbd_cdc_itf, (const uint8_t*)str, len); } -#endif } /******************************************************************************/ @@ -212,13 +213,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: @@ -249,9 +253,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // check if user wants to disable the USB if (args[0].u_obj == mp_const_none) { // disable usb - #if defined(USE_DEVICE_MODE) pyb_usb_dev_deinit(); - #endif return mp_const_none; } @@ -268,7 +270,7 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t * goto bad_mode; } -#elif defined(USE_DEVICE_MODE) +#else // hardware configured for USB device mode @@ -293,6 +295,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; } @@ -315,14 +322,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; @@ -600,7 +610,6 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t * STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_hid_recv_obj, 1, pyb_usb_hid_recv); STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { -#ifdef USE_DEVICE_MODE pyb_usb_vcp_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_buffer_info_t bufinfo; byte temp_buf[8]; @@ -624,7 +633,6 @@ STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) { } else { return mp_obj_new_int(0); } -#endif return mp_const_none; } @@ -738,3 +746,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 41c461fb2..6b43af00f 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,7 @@ #define USBD_PID_CDC_MSC (0x9800) #define USBD_PID_CDC_HID (0x9801) #define USBD_PID_CDC (0x9802) +#define USBD_PID_MSC (0x9803) typedef enum { PYB_USB_STORAGE_MEDIUM_NONE = 0, @@ -68,4 +69,4 @@ void pyb_usb_host_init(void); void pyb_usb_host_process(void); uint pyb_usb_host_get_keyboard(void); -#endif // MICROPY_INCLUDED_STMHAL_USB_H +#endif // MICROPY_INCLUDED_STM32_USB_H diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c index 2e9fba917..23085510c 100644 --- a/ports/stm32/usbd_cdc_interface.c +++ b/ports/stm32/usbd_cdc_interface.c @@ -198,7 +198,7 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) { // the host waits for all data to arrive (ie, waits for a packet < max packet size). // To flush a packet of exactly max packet size, we need to send a zero-size packet. // See eg http://www.cypress.com/?id=4&rID=92719 - cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % CDC_DATA_FS_MAX_PACKET_SIZE == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); + cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in); } } } diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h index 98b8fc077..36a89e7db 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 /** ****************************************************************************** @@ -37,7 +37,7 @@ typedef struct _usbd_cdc_itf_t { usbd_cdc_msc_hid_state_t *usbd; // the parent USB device - uint8_t rx_packet_buf[CDC_DATA_FS_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer + uint8_t rx_packet_buf[CDC_DATA_MAX_PACKET_SIZE]; // received data from USB OUT endpoint is stored in this buffer uint8_t rx_user_buf[USBD_CDC_RX_DATA_SIZE]; // received data is buffered here until the user reads it volatile uint16_t rx_buf_put; // circular buffer index uint16_t rx_buf_get; // circular buffer index @@ -63,4 +63,4 @@ void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len); int usbd_cdc_rx_num(usbd_cdc_itf_t *cdc); int usbd_cdc_rx(usbd_cdc_itf_t *cdc, uint8_t *buf, uint32_t len, uint32_t timeout); -#endif // MICROPY_INCLUDED_STMHAL_USBD_CDC_INTERFACE_H +#endif // MICROPY_INCLUDED_STM32_USBD_CDC_INTERFACE_H diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c index d39144851..fe05e2e4c 100644 --- a/ports/stm32/usbd_conf.c +++ b/ports/stm32/usbd_conf.c @@ -39,10 +39,10 @@ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ -#ifdef USE_USB_FS +#if MICROPY_HW_USB_FS PCD_HandleTypeDef pcd_fs_handle; #endif -#ifdef USE_USB_HS +#if MICROPY_HW_USB_HS PCD_HandleTypeDef pcd_hs_handle; #endif /* Private function prototypes -----------------------------------------------*/ @@ -63,13 +63,17 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) if(hpcd->Instance == USB_OTG_FS) { /* Configure USB FS GPIOs */ - __GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12); GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + #if defined(STM32H7) + GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_FS; + #else GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + #endif HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Configure VBUS Pin */ @@ -86,14 +90,19 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); #endif + #if defined(STM32H7) + // Keep USB clock running during sleep or else __WFI() will disable the USB + __HAL_RCC_USB2_OTG_FS_CLK_SLEEP_ENABLE(); + __HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE(); + #endif + /* Enable USB FS Clocks */ __USB_OTG_FS_CLK_ENABLE(); -#if defined (MCU_SERIES_L4) +#if defined(STM32L4) /* Enable VDDUSB */ if(__HAL_RCC_PWR_IS_CLK_DISABLED()) { @@ -113,19 +122,19 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USBFS Interrupt */ HAL_NVIC_EnableIRQ(OTG_FS_IRQn); } -#if defined(USE_USB_HS) +#if MICROPY_HW_USB_HS else if(hpcd->Instance == USB_OTG_HS) { -#if defined(USE_USB_HS_IN_FS) +#if MICROPY_HW_USB_HS_IN_FS /* Configure USB FS GPIOs */ - __GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); /* Configure DM DP Pins */ GPIO_InitStruct.Pin = (GPIO_PIN_14 | GPIO_PIN_15); GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); @@ -134,7 +143,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); #endif @@ -144,7 +153,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); #endif @@ -152,25 +161,34 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) * Enable calling WFI and correct * function of the embedded USB_FS_IN_HS phy */ - __OTGHSULPI_CLK_SLEEP_DISABLE(); - __OTGHS_CLK_SLEEP_ENABLE(); - /* Enable USB HS Clocks */ - __USB_OTG_HS_CLK_ENABLE(); + __HAL_RCC_USB_OTG_HS_ULPI_CLK_SLEEP_DISABLE(); + __HAL_RCC_USB_OTG_HS_CLK_SLEEP_ENABLE(); -#else // !USE_USB_HS_IN_FS + /* 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 /* Configure USB HS GPIOs */ - __GPIOA_CLK_ENABLE(); - __GPIOB_CLK_ENABLE(); - __GPIOC_CLK_ENABLE(); - __GPIOH_CLK_ENABLE(); - __GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); /* CLK */ GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); @@ -178,7 +196,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); @@ -214,7 +232,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USB HS Clocks */ __USB_OTG_HS_CLK_ENABLE(); __USB_OTG_HS_ULPI_CLK_ENABLE(); -#endif // !USE_USB_HS_IN_FS +#endif // !MICROPY_HW_USB_HS_IN_FS /* Set USBHS Interrupt to the lowest priority */ HAL_NVIC_SetPriority(OTG_HS_IRQn, IRQ_PRI_OTG_HS, IRQ_SUBPRI_OTG_HS); @@ -222,7 +240,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USBHS Interrupt */ HAL_NVIC_EnableIRQ(OTG_HS_IRQn); } -#endif // USE_USB_HS +#endif // MICROPY_HW_USB_HS } /** * @brief DeInitializes the PCD MSP. @@ -237,7 +255,7 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) __USB_OTG_FS_CLK_DISABLE(); __SYSCFG_CLK_DISABLE(); } - #if defined(USE_USB_HS) + #if MICROPY_HW_USB_HS else if(hpcd->Instance == USB_OTG_HS) { /* Disable USB FS Clocks */ @@ -399,9 +417,9 @@ void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) * @param pdev: Device handle * @retval USBD Status */ -USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev) +USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed) { -#if defined(USE_USB_FS) +#if MICROPY_HW_USB_FS if (pdev->id == USB_PHY_FS_ID) { /*Set LL Driver parameters */ @@ -414,7 +432,7 @@ if (pdev->id == USB_PHY_FS_ID) pcd_fs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; pcd_fs_handle.Init.Sof_enable = 1; pcd_fs_handle.Init.speed = PCD_SPEED_FULL; -#if defined(MCU_SERIES_L4) +#if defined(STM32L4) pcd_fs_handle.Init.lpm_enable = DISABLE; pcd_fs_handle.Init.battery_charging_enable = DISABLE; #endif @@ -436,10 +454,10 @@ if (pdev->id == USB_PHY_FS_ID) HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 0x40); } #endif -#if defined(USE_USB_HS) +#if MICROPY_HW_USB_HS if (pdev->id == USB_PHY_HS_ID) { -#if defined(USE_USB_HS_IN_FS) +#if MICROPY_HW_USB_HS_IN_FS /*Set LL Driver parameters */ pcd_hs_handle.Instance = USB_OTG_HS; pcd_hs_handle.Init.dev_endpoints = 4; @@ -447,26 +465,35 @@ if (pdev->id == USB_PHY_HS_ID) pcd_hs_handle.Init.ep0_mps = 0x40; pcd_hs_handle.Init.dma_enable = 0; pcd_hs_handle.Init.low_power_enable = 0; + #if defined(STM32F723xx) || defined(STM32F733xx) + pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; + #else pcd_hs_handle.Init.phy_itface = PCD_PHY_EMBEDDED; + #endif pcd_hs_handle.Init.Sof_enable = 1; - pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL; + if (high_speed) { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + } else { + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH_IN_FULL; + } #if !defined(MICROPY_HW_USB_VBUS_DETECT_PIN) pcd_hs_handle.Init.vbus_sensing_enable = 0; // No VBUS Sensing on USB0 #else pcd_hs_handle.Init.vbus_sensing_enable = 1; #endif + pcd_hs_handle.Init.use_external_vbus = 0; /* Link The driver to the stack */ pcd_hs_handle.pData = pdev; pdev->pData = &pcd_hs_handle; /*Initialize LL Driver */ HAL_PCD_Init(&pcd_hs_handle); - HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x80); + HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200); HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x40); + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x100); HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20); - HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0x40); -#else // !defined(USE_USB_HS_IN_FS) + HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0xc0); +#else // !MICROPY_HW_USB_HS_IN_FS /*Set LL Driver parameters */ pcd_hs_handle.Instance = USB_OTG_HS; pcd_hs_handle.Init.dev_endpoints = 6; @@ -495,9 +522,9 @@ if (pdev->id == USB_PHY_HS_ID) HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x80); HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x174); -#endif // !USE_USB_HS_IN_FS +#endif // !MICROPY_HW_USB_HS_IN_FS } -#endif // USE_USB_HS +#endif // MICROPY_HW_USB_HS return USBD_OK; } diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h index 34ebe27b9..bf96b7b49 100644 --- a/ports/stm32/usbd_conf.h +++ b/ports/stm32/usbd_conf.h @@ -34,19 +34,17 @@ #define __USBD_CONF_H /* Includes ------------------------------------------------------------------*/ +#include #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 diff --git a/ports/stm32/usbd_desc.c b/ports/stm32/usbd_desc.c index 1de75aee0..4babebf64 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 a4de6c681..0307defa5 100644 --- a/ports/stm32/usbd_desc.h +++ b/ports/stm32/usbd_desc.h @@ -23,8 +23,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_DESC_H -#define MICROPY_INCLUDED_STMHAL_USBD_DESC_H +#ifndef MICROPY_INCLUDED_STM32_USBD_DESC_H +#define MICROPY_INCLUDED_STM32_USBD_DESC_H #include "usbd_cdc_msc_hid.h" @@ -32,4 +32,4 @@ extern const USBD_DescriptorsTypeDef USBD_Descriptors; void USBD_SetVIDPIDRelease(usbd_cdc_msc_hid_state_t *usbd, uint16_t vid, uint16_t pid, uint16_t device_release_num, int cdc_only); -#endif // MICROPY_INCLUDED_STMHAL_USBD_DESC_H +#endif // MICROPY_INCLUDED_STM32_USBD_DESC_H diff --git a/ports/stm32/usbd_hid_interface.h b/ports/stm32/usbd_hid_interface.h index 79040b57e..d9adf8a5f 100644 --- a/ports/stm32/usbd_hid_interface.h +++ b/ports/stm32/usbd_hid_interface.h @@ -1,8 +1,8 @@ /* * This file is part of the MicroPython project, http://micropython.org/ */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H -#define MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H +#ifndef MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H +#define MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H #include "usbd_cdc_msc_hid.h" @@ -18,4 +18,4 @@ typedef struct _usbd_hid_itf_t { int usbd_hid_rx_num(usbd_hid_itf_t *hid); int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout); -#endif // MICROPY_INCLUDED_STMHAL_USBD_HID_INTERFACE_H +#endif // MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H diff --git a/ports/stm32/usbd_msc_storage.c b/ports/stm32/usbd_msc_storage.c index f825c3d70..7d6c19e9f 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 6cc40d2d6..669f7df58 100644 --- a/ports/stm32/usbd_msc_storage.h +++ b/ports/stm32/usbd_msc_storage.h @@ -23,10 +23,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H -#define MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H +#ifndef MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H +#define MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H extern const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops; extern const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops; -#endif // MICROPY_INCLUDED_STMHAL_USBD_MSC_STORAGE_H +#endif // MICROPY_INCLUDED_STM32_USBD_MSC_STORAGE_H diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h index a26b1df0d..217712701 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,32 @@ #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 #define MAX_TEMPLATE_CONFIG_DESC_SIZE (107) // CDC, MSC and HID packet sizes +#define MSC_FS_MAX_PACKET (64) +#define MSC_HS_MAX_PACKET (512) #define CDC_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size +#define CDC_DATA_HS_MAX_PACKET_SIZE (512) // endpoint IN & OUT packet size +#if USBD_SUPPORT_HS_MODE +#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_HS_MAX_PACKET_SIZE +#else +#define CDC_DATA_MAX_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE +#endif #define MSC_MEDIA_PACKET (2048) // was 8192; how low can it go whilst still working? #define HID_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size @@ -32,12 +52,12 @@ typedef struct { } USBD_CDC_LineCodingTypeDef; typedef struct { - uint32_t data[CDC_DATA_FS_MAX_PACKET_SIZE/4]; /* Force 32bits alignment */ + uint32_t data[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32bits alignment uint8_t CmdOpCode; uint8_t CmdLength; - __IO uint32_t TxState; - __IO uint32_t RxState; + volatile uint32_t TxState; + volatile uint32_t RxState; } USBD_CDC_HandleTypeDef; typedef struct _USBD_STORAGE { @@ -126,6 +146,28 @@ extern const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_ extern const USBD_ClassTypeDef USBD_CDC_MSC_HID; +static inline uint32_t usbd_msc_max_packet(USBD_HandleTypeDef *pdev) { + #if USBD_SUPPORT_HS_MODE + if (pdev->dev_speed == USBD_SPEED_HIGH) { + return MSC_HS_MAX_PACKET; + } else + #endif + { + return MSC_FS_MAX_PACKET; + } +} + +static inline uint32_t usbd_cdc_max_packet(USBD_HandleTypeDef *pdev) { + #if USBD_SUPPORT_HS_MODE + if (pdev->dev_speed == USBD_SPEED_HIGH) { + return CDC_DATA_HS_MAX_PACKET_SIZE; + } else + #endif + { + return CDC_DATA_FS_MAX_PACKET_SIZE; + } +} + // returns 0 on success, -1 on failure int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info); // returns the current usb mode diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h index 08882bb1a..95fc693a0 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 @@ -37,6 +37,7 @@ typedef enum { USBD_MODE_CDC_MSC = 0x03, USBD_MODE_CDC_HID = 0x05, USBD_MODE_MSC_HID = 0x06, + USBD_MODE_HIGH_SPEED = 0x80, // or with one of the above } usb_device_mode_t; typedef struct _USBD_HID_ModeInfoTypeDef { @@ -48,4 +49,4 @@ typedef struct _USBD_HID_ModeInfoTypeDef { const uint8_t *report_desc; } USBD_HID_ModeInfoTypeDef; -#endif // MICROPY_INCLUDED_STMHAL_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H +#endif // MICROPY_INCLUDED_STM32_USBDEV_CLASS_INC_USBD_CDC_MSC_HID0_H diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c index 379a8f32c..a1a7cff6c 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,25 @@ * THE SOFTWARE. */ +#include STM32_HAL_H #include "usbd_ioreq.h" #include "usbd_cdc_msc_hid.h" +#define MSC_TEMPLATE_CONFIG_DESC_SIZE (32) +#define MSC_TEMPLATE_MSC_DESC_OFFSET (9) #define CDC_TEMPLATE_CONFIG_DESC_SIZE (67) #define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98) +#define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9) +#define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40) #define CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107) #define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9) +#define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49) +#define CDC_TEMPLATE_CDC_DESC_OFFSET (9) +#define CDC_DESC_OFFSET_INTR_INTERVAL (34) +#define CDC_DESC_OFFSET_OUT_MAX_PACKET_LO (48) +#define CDC_DESC_OFFSET_OUT_MAX_PACKET_HI (49) +#define CDC_DESC_OFFSET_IN_MAX_PACKET_LO (55) +#define CDC_DESC_OFFSET_IN_MAX_PACKET_HI (56) #define HID_DESC_OFFSET_SUBCLASS (6) #define HID_DESC_OFFSET_PROTOCOL (7) #define HID_DESC_OFFSET_SUBDESC (9) @@ -57,10 +69,7 @@ #define USB_DESC_TYPE_ASSOCIATION (0x0b) #define CDC_CMD_PACKET_SIZE (8) // Control Endpoint Packet size -#define CDC_DATA_IN_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE -#define CDC_DATA_OUT_PACKET_SIZE CDC_DATA_FS_MAX_PACKET_SIZE -#define MSC_MAX_PACKET (0x40) #define BOT_GET_MAX_LUN (0xfe) #define BOT_RESET (0xff) @@ -71,8 +80,7 @@ #define HID_REQ_SET_IDLE (0x0a) #define HID_REQ_GET_IDLE (0x02) -/* -// this is used only in high-speed mode, which we don't support +#if USBD_SUPPORT_HS_MODE // USB Standard Device Descriptor __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_HID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = { USB_LEN_DEV_QUALIFIER_DESC, @@ -82,11 +90,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 +178,8 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type MSC_IN_EP, // bEndpointAddress: IN, address 3 0x02, // bmAttributes: Bulk endpoint type - LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_MAX_PACKET), + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), 0x00, // bInterval: ignore for Bulk transfer // Endpoint OUT descriptor @@ -131,8 +187,8 @@ static const uint8_t cdc_msc_template_config_desc[CDC_MSC_TEMPLATE_CONFIG_DESC_S USB_DESC_TYPE_ENDPOINT, // bDescriptorType: Endpoint descriptor type MSC_OUT_EP, // bEndpointAddress: OUT, address 3 0x02, // bmAttributes: Bulk endpoint type - LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize - HIBYTE(MSC_MAX_PACKET), + LOBYTE(MSC_FS_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_FS_MAX_PACKET), 0x00, // bInterval: ignore for Bulk transfer //========================================================================== @@ -553,6 +609,11 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode // construct config desc switch (usbd->usbd_mode) { + case USBD_MODE_MSC: + usbd->usbd_config_desc_size = sizeof(msc_template_config_desc); + memcpy(usbd->usbd_config_desc, msc_template_config_desc, sizeof(msc_template_config_desc)); + break; + case USBD_MODE_CDC_MSC: usbd->usbd_config_desc_size = sizeof(cdc_msc_template_config_desc); memcpy(usbd->usbd_config_desc, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc)); @@ -608,27 +669,31 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode } static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { + #if !USBD_SUPPORT_HS_MODE if (pdev->dev_speed == USBD_SPEED_HIGH) { // can't handle high speed return 1; } + #endif usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; if (usbd->usbd_mode & USBD_MODE_CDC) { // CDC VCP component + int mp = usbd_cdc_max_packet(pdev); + // Open EP IN USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK, - CDC_DATA_IN_PACKET_SIZE); + mp); // Open EP OUT USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK, - CDC_DATA_OUT_PACKET_SIZE); + mp); // Open Command IN EP USBD_LL_OpenEP(pdev, @@ -644,23 +709,25 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { usbd->CDC_ClassData.RxState = 0; // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, CDC_DATA_OUT_PACKET_SIZE); + USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, mp); } if (usbd->usbd_mode & USBD_MODE_MSC) { // MSC component + int mp = usbd_msc_max_packet(pdev); + // Open EP OUT USBD_LL_OpenEP(pdev, MSC_OUT_EP, USBD_EP_TYPE_BULK, - MSC_MAX_PACKET); + mp); // Open EP IN USBD_LL_OpenEP(pdev, MSC_IN_EP, USBD_EP_TYPE_BULK, - MSC_MAX_PACKET); + mp); // Init the BOT layer MSC_BOT_Init(pdev); @@ -754,13 +821,45 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + // Work out the recipient of the setup request + uint8_t mode = usbd->usbd_mode; + uint8_t recipient = 0; + switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) { + case USB_REQ_RECIPIENT_INTERFACE: { + uint16_t iface = req->wIndex; + if ((mode & USBD_MODE_CDC) && iface == usbd->cdc_iface_num) { + recipient = USBD_MODE_CDC; + } else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) { + recipient = USBD_MODE_MSC; + } else if ((mode & USBD_MODE_HID) && iface == usbd->hid_iface_num) { + recipient = USBD_MODE_HID; + } + break; + } + case USB_REQ_RECIPIENT_ENDPOINT: { + uint8_t ep = req->wIndex & 0x7f; + if ((mode & USBD_MODE_CDC) && (ep == CDC_OUT_EP || ep == (CDC_CMD_EP & 0x7f))) { + recipient = USBD_MODE_CDC; + } else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) { + recipient = USBD_MODE_MSC; + } else if ((mode & USBD_MODE_HID) && ep == usbd->hid_out_ep) { + recipient = USBD_MODE_HID; + } + break; + } + } + + // Fail the request if we didn't have a valid recipient + if (recipient == 0) { + USBD_CtlError(pdev, req); + return USBD_FAIL; + } + switch (req->bmRequest & USB_REQ_TYPE_MASK) { // Class request case USB_REQ_TYPE_CLASS: - // req->wIndex is the recipient interface number - if ((usbd->usbd_mode & USBD_MODE_CDC) && req->wIndex == usbd->cdc_iface_num) { - // CDC component + if (recipient == USBD_MODE_CDC) { if (req->wLength) { if (req->bmRequest & 0x80) { // device-to-host request @@ -777,8 +876,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp // Transfer the command to the interface layer return usbd_cdc_control(usbd->cdc, req->bRequest, NULL, req->wValue); } - } else if ((usbd->usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) { - // MSC component + } else if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { case BOT_GET_MAX_LUN: if ((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) { @@ -803,7 +901,7 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp USBD_CtlError(pdev, req); return USBD_FAIL; } - } else if ((usbd->usbd_mode & USBD_MODE_HID) && req->wIndex == usbd->hid_iface_num) { + } else if (recipient == USBD_MODE_HID) { switch (req->bRequest) { case HID_REQ_SET_PROTOCOL: usbd->HID_ClassData.Protocol = (uint8_t)(req->wValue); @@ -828,9 +926,8 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp } break; - // Interface & Endpoint request case USB_REQ_TYPE_STANDARD: - if ((usbd->usbd_mode & USBD_MODE_MSC) && req->wIndex == MSC_IFACE_NUM_WITH_CDC) { + if (recipient == USBD_MODE_MSC) { switch (req->bRequest) { case USB_REQ_GET_INTERFACE : USBD_CtlSendData(pdev, (uint8_t *)&usbd->MSC_BOT_ClassData.interface, 1); @@ -848,16 +945,16 @@ 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; @@ -945,18 +1042,66 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) { usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData; + + #if USBD_SUPPORT_HS_MODE + uint8_t *cdc_desc = NULL; + uint8_t *msc_desc = NULL; + switch (usbd->usbd_mode) { + case USBD_MODE_MSC: + msc_desc = usbd->usbd_config_desc + MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + + case USBD_MODE_CDC_MSC: + cdc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_CDC_DESC_OFFSET; + msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET; + break; + + case USBD_MODE_CDC_HID: + cdc_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET; + break; + + case USBD_MODE_CDC: + cdc_desc = usbd->usbd_config_desc + CDC_TEMPLATE_CDC_DESC_OFFSET; + break; + } + + // configure CDC descriptors, if needed + if (cdc_desc != NULL) { + uint32_t mp = usbd_cdc_max_packet(pdev); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp); + cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp); + uint8_t interval; // polling interval in frames of 1ms + if (pdev->dev_speed == USBD_SPEED_HIGH) { + interval = 0x09; + } else { + interval = 0x20; + } + cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval; + } + + if (msc_desc != NULL) { + uint32_t mp = usbd_msc_max_packet(pdev); + msc_desc[13] = LOBYTE(mp); + msc_desc[14] = HIBYTE(mp); + msc_desc[20] = LOBYTE(mp); + msc_desc[21] = HIBYTE(mp); + } + #endif + *length = usbd->usbd_config_desc_size; return usbd->usbd_config_desc; } -// this is used only in high-speed mode, which we don't support uint8_t *USBD_CDC_MSC_HID_GetDeviceQualifierDescriptor(USBD_HandleTypeDef *pdev, uint16_t *length) { - /* + #if USBD_SUPPORT_HS_MODE *length = sizeof(USBD_CDC_MSC_HID_DeviceQualifierDesc); return USBD_CDC_MSC_HID_DeviceQualifierDesc; - */ + #else *length = 0; return NULL; + #endif } // data received on non-control OUT endpoint @@ -976,12 +1121,15 @@ uint8_t USBD_CDC_TransmitPacket(usbd_cdc_msc_hid_state_t *usbd, size_t len, cons // prepare OUT endpoint for reception uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { // Suspend or Resume USB Out process + + #if !USBD_SUPPORT_HS_MODE if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) { return USBD_FAIL; } + #endif // Prepare Out endpoint to receive next packet - USBD_LL_PrepareReceive(usbd->pdev, CDC_OUT_EP, buf, CDC_DATA_OUT_PACKET_SIZE); + USBD_LL_PrepareReceive(usbd->pdev, CDC_OUT_EP, buf, usbd_cdc_max_packet(usbd->pdev)); return USBD_OK; } @@ -989,9 +1137,12 @@ uint8_t USBD_CDC_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { // prepare OUT endpoint for reception uint8_t USBD_HID_ReceivePacket(usbd_cdc_msc_hid_state_t *usbd, uint8_t *buf) { // Suspend or Resume USB Out process + + #if !USBD_SUPPORT_HS_MODE if (usbd->pdev->dev_speed == USBD_SPEED_HIGH) { return USBD_FAIL; } + #endif // Prepare Out endpoint to receive next packet uint16_t mps_out = diff --git a/ports/stm32/usbdev/core/inc/usbd_core.h b/ports/stm32/usbdev/core/inc/usbd_core.h index 3178d4a4b..fb1d541f6 100644 --- a/ports/stm32/usbdev/core/inc/usbd_core.h +++ b/ports/stm32/usbdev/core/inc/usbd_core.h @@ -111,7 +111,7 @@ USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev); USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev); /* USBD Low Level Driver */ -USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev); +USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev, int high_speed); USBD_StatusTypeDef USBD_LL_DeInit (USBD_HandleTypeDef *pdev); USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev); USBD_StatusTypeDef USBD_LL_Stop (USBD_HandleTypeDef *pdev); diff --git a/ports/stm32/usbdev/core/inc/usbd_def.h b/ports/stm32/usbdev/core/inc/usbd_def.h index 888d426ef..140206296 100644 --- a/ports/stm32/usbdev/core/inc/usbd_def.h +++ b/ports/stm32/usbdev/core/inc/usbd_def.h @@ -172,9 +172,6 @@ typedef struct _Device_cb uint8_t *(*GetFSConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); uint8_t *(*GetOtherSpeedConfigDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); uint8_t *(*GetDeviceQualifierDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); -#if (USBD_SUPPORT_USER_STRING == 1) - uint8_t *(*GetUsrStrDescriptor)(struct _USBD_HandleTypeDef *pdev ,uint8_t index, uint16_t *length); -#endif } USBD_ClassTypeDef; @@ -199,12 +196,7 @@ struct _USBD_HandleTypeDef; typedef struct { uint8_t *(*GetDeviceDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetLangIDStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetManufacturerStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetProductStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetSerialStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetConfigurationStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); - uint8_t *(*GetInterfaceStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint16_t *length); + uint8_t *(*GetStrDescriptor)(struct _USBD_HandleTypeDef *pdev, uint8_t idx, uint16_t *length); } USBD_DescriptorsTypeDef; /* USB Device handle structure */ diff --git a/ports/stm32/usbdev/core/src/usbd_core.c b/ports/stm32/usbdev/core/src/usbd_core.c index ae5b99626..23d2bc09f 100644 --- a/ports/stm32/usbdev/core/src/usbd_core.c +++ b/ports/stm32/usbdev/core/src/usbd_core.c @@ -119,7 +119,7 @@ USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef * pdev->dev_state = USBD_STATE_DEFAULT; pdev->id = id; /* Initialize low level driver */ - USBD_LL_Init(pdev); + USBD_LL_Init(pdev, 0); return USBD_OK; } diff --git a/ports/stm32/usbdev/core/src/usbd_ctlreq.c b/ports/stm32/usbdev/core/src/usbd_ctlreq.c index 5fba322fa..a68016bf4 100644 --- a/ports/stm32/usbdev/core/src/usbd_ctlreq.c +++ b/ports/stm32/usbdev/core/src/usbd_ctlreq.c @@ -347,42 +347,13 @@ static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , break; case USB_DESC_TYPE_STRING: - switch ((uint8_t)(req->wValue)) - { - case USBD_IDX_LANGID_STR: - pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev, &len); - break; - - case USBD_IDX_MFC_STR: - pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev, &len); - break; - - case USBD_IDX_PRODUCT_STR: - pbuf = pdev->pDesc->GetProductStrDescriptor(pdev, &len); - break; - - case USBD_IDX_SERIAL_STR: - pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev, &len); - break; - - case USBD_IDX_CONFIG_STR: - pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev, &len); - break; - - case USBD_IDX_INTERFACE_STR: - pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev, &len); - break; - - default: -#if (USBD_SUPPORT_USER_STRING == 1) - pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue) , &len); - break; -#else - USBD_CtlError(pdev , req); + pbuf = pdev->pDesc->GetStrDescriptor(pdev, req->wValue & 0xff, &len); + if (pbuf == NULL) { + USBD_CtlError(pdev, req); return; -#endif } break; + case USB_DESC_TYPE_DEVICE_QUALIFIER: if(pdev->dev_speed == USBD_SPEED_HIGH ) diff --git a/ports/stm32/usrsw.c b/ports/stm32/usrsw.c index a7721ad77..ded0b6864 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 d96e3c281..a8a087db2 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 2b4967a43..8df7b4768 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 0a486f704..d60bb7e9e 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 e65d03410..f9e137602 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 add052fad..cf59dbd0a 100644 --- a/ports/teensy/led.c +++ b/ports/teensy/led.c @@ -33,7 +33,7 @@ void led_init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* Configure I/O speed, mode, output type and pull */ - GPIO_InitStructure.Speed = GPIO_SPEED_LOW; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Mode = MICROPY_HW_LED_OTYPE; GPIO_InitStructure.Pull = GPIO_NOPULL; diff --git a/ports/teensy/teensy_hal.h b/ports/teensy/teensy_hal.h index 162effa85..aef38a2ad 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 b5f9f8e7d..cbdd3f3fb 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) @@ -258,6 +257,7 @@ coverage_test: coverage cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests -d thread cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --emit native cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/micropython_coverage ./run-tests --via-mpy -d basics float + cat $(TOP)/tests/basics/0prelim.py | ./micropython_coverage | grep -q 'abc' gcov -o build-coverage/py $(TOP)/py/*.c gcov -o build-coverage/extmod $(TOP)/extmod/*.c diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 5118f9052..eba84f38b 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) @@ -150,7 +152,11 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%.2s %.3s\n", "abc", "abc"); // fixed string precision mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools + #ifndef NDEBUG mp_printf(&mp_plat_print, "%s\n", NULL); // null string + #else + mp_printf(&mp_plat_print, "(null)\n"); // without debugging mp_printf won't check for null + #endif mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned @@ -158,6 +164,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"); @@ -231,6 +254,16 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); } + // bytearray + { + mp_printf(&mp_plat_print, "# bytearray\n"); + + // create a bytearray via mp_obj_new_bytearray + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(mp_obj_new_bytearray(4, "data"), &bufinfo, MP_BUFFER_RW); + mp_printf(&mp_plat_print, "%.*s\n", bufinfo.len, bufinfo.buf); + } + // mpz { mp_printf(&mp_plat_print, "# mpz\n"); @@ -252,6 +285,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/mpconfigport.h b/ports/unix/mpconfigport.h index 353bfa3e4..06dae9da8 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -97,6 +97,7 @@ #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_STDFILES (1) #define MICROPY_PY_SYS_EXC_INFO (1) +#define MICROPY_PY_COLLECTIONS_DEQUE (1) #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #ifndef MICROPY_PY_MATH_SPECIAL_FUNCTIONS #define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1) diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index cf976bf7a..b3fcd1e6b 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -36,6 +36,7 @@ #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_PY_DELATTR_SETATTR (1) #define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) +#define MICROPY_PY_BUILTINS_RANGE_BINOP (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_MODULES (1) #define MICROPY_PY_SYS_GETSIZEOF (1) diff --git a/ports/windows/.appveyor.yml b/ports/windows/.appveyor.yml index a82cf5adc..795330eff 100644 --- a/ports/windows/.appveyor.yml +++ b/ports/windows/.appveyor.yml @@ -24,6 +24,26 @@ test_script: %MICROPY_CPYTHON3% run-tests +# After the build/test phase for the MSVC build completes, +# build and test with mingw-w64, release versions only. +after_test: +- ps: | + if ($env:configuration -eq 'Debug') { + return + } + $env:MSYSTEM = if ($platform -eq 'x86') {'MINGW32'} else {'MINGW64'} + $env:CHERE_INVOKING = 'enabled_from_arguments' + cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'ports/windows') + C:\msys64\usr\bin\bash.exe -l -c "make -B -j4 V=1" + if ($LASTEXITCODE -ne 0) { + throw "$env:MSYSTEM build exited with code $LASTEXITCODE" + } + cd (Join-Path $env:APPVEYOR_BUILD_FOLDER 'tests') + & $env:MICROPY_CPYTHON3 run-tests -e math_fun -e float2int_double -e float_parse -e math_domain_special + if ($LASTEXITCODE -ne 0) { + throw "$env:MSYSTEM tests exited with code $LASTEXITCODE" + } + skip_tags: true deploy: off diff --git a/ports/windows/Makefile b/ports/windows/Makefile index b6433300f..725cb686e 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 abad35282..9db6d31ce 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/Makefile b/ports/zephyr/Makefile index 2064fcef7..49a6f6718 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -82,7 +82,7 @@ build/genhdr/qstr.i.last: | $(Z_EXPORTS) LIBMICROPYTHON_EXTRA_CMD = -$(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk # MicroPython's global clean cleans everything, fast -CLEAN_EXTRA = outdir prj_*_merged.conf +CLEAN_EXTRA = outdir libmicropython.a prj_*_merged.conf # Clean Zephyr things in Zephyr way z_clean: diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c index 8c64fdcee..58d127ec6 100644 --- a/ports/zephyr/main.c +++ b/ports/zephyr/main.c @@ -51,21 +51,6 @@ static char *stack_top; static char heap[MICROPY_HEAP_SIZE]; -void do_str(const char *src, mp_parse_input_kind_t input_kind) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - qstr source_name = lex->source_name; - mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true); - mp_call_function_0(module_fun); - nlr_pop(); - } else { - // uncaught exception - mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); - } -} - void init_zephyr(void) { // We now rely on CONFIG_NET_APP_SETTINGS to set up bootstrap // network addresses. diff --git a/py/asmarm.c b/py/asmarm.c index 552fdfb34..1a8923bc2 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -150,10 +150,7 @@ void asm_arm_bkpt(asm_arm_t *as) { // | low address | high address in RAM void asm_arm_entry(asm_arm_t *as, int num_locals) { - - if (num_locals < 0) { - num_locals = 0; - } + assert(num_locals >= 0); as->stack_adjust = 0; as->push_reglist = 1 << ASM_ARM_REG_R1 diff --git a/py/asmthumb.c b/py/asmthumb.c index 5316a7efb..c5b45f2f5 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -104,6 +104,8 @@ STATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) { // | low address | high address in RAM void asm_thumb_entry(asm_thumb_t *as, int num_locals) { + assert(num_locals >= 0); + // work out what to push and how many extra spaces to reserve on stack // so that we have enough for all locals and it's aligned an 8-byte boundary // we push extra regs (r1, r2, r3) to help do the stack adjustment @@ -111,9 +113,6 @@ void asm_thumb_entry(asm_thumb_t *as, int num_locals) { // for push rlist, lowest numbered register at the lowest address uint reglist; uint stack_adjust; - if (num_locals < 0) { - num_locals = 0; - } // don't pop r0 because it's used for return value switch (num_locals) { case 0: diff --git a/py/asmx64.c b/py/asmx64.c index aa2a8ec7c..c900a08d1 100644 --- a/py/asmx64.c +++ b/py/asmx64.c @@ -526,11 +526,9 @@ void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) { } void asm_x64_entry(asm_x64_t *as, int num_locals) { + assert(num_locals >= 0); asm_x64_push_r64(as, ASM_X64_REG_RBP); asm_x64_mov_r64_r64(as, ASM_X64_REG_RBP, ASM_X64_REG_RSP); - if (num_locals < 0) { - num_locals = 0; - } num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, num_locals * WORD_SIZE); asm_x64_push_r64(as, ASM_X64_REG_RBX); diff --git a/py/asmx86.c b/py/asmx86.c index 6a78fbd5e..3938baaac 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 bd5895453..09559850c 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); diff --git a/py/builtinimport.c b/py/builtinimport.c index 97c1789f8..b8ed096ca 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -44,6 +44,8 @@ #define DEBUG_printf(...) (void)0 #endif +#if MICROPY_ENABLE_EXTERNAL_IMPORT + #define PATH_SEP_CHAR '/' bool mp_obj_is_package(mp_obj_t module) { @@ -389,19 +391,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } // found weak linked module module_obj = el->value; - if (MICROPY_MODULE_BUILTIN_INIT) { - // look for __init__ and call it if it exists - // Note: this code doesn't work fully correctly because it allows the - // __init__ function to be called twice if the module is imported by its - // non-weak-link name. Also, this code is duplicated in objmodule.c. - mp_obj_t dest[2]; - mp_load_method_maybe(el->value, MP_QSTR___init__, dest); - if (dest[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, dest); - // register module so __init__ is not called again - mp_module_register(mod_name, el->value); - } - } + mp_module_call_init(mod_name, module_obj); } else { no_exist: #else @@ -485,4 +475,41 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // Otherwise, we need to return top-level package return top_module_obj; } + +#else // MICROPY_ENABLE_EXTERNAL_IMPORT + +mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { + // Check that it's not a relative import + if (n_args >= 5 && MP_OBJ_SMALL_INT_VALUE(args[4]) != 0) { + mp_raise_NotImplementedError("relative import"); + } + + // Check if module already exists, and return it if it does + qstr module_name_qstr = mp_obj_str_get_qstr(args[0]); + mp_obj_t module_obj = mp_module_get(module_name_qstr); + if (module_obj != MP_OBJ_NULL) { + return module_obj; + } + + #if MICROPY_MODULE_WEAK_LINKS + // Check if there is a weak link to this module + mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(module_name_qstr), MP_MAP_LOOKUP); + if (el != NULL) { + // Found weak-linked module + mp_module_call_init(module_name_qstr, el->value); + return el->value; + } + #endif + + // Couldn't find the module, so fail + if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { + mp_raise_msg(&mp_type_ImportError, "module not found"); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, + "no module named '%q'", module_name_qstr)); + } +} + +#endif // MICROPY_ENABLE_EXTERNAL_IMPORT + MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__); diff --git a/py/compile.c b/py/compile.c index 52d10ee5e..9200b346b 100644 --- a/py/compile.c +++ b/py/compile.c @@ -376,6 +376,7 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as EMIT(store_subscr); } } + return; } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) { assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); if (assign_kind == ASSIGN_AUG_LOAD) { @@ -387,16 +388,10 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as } EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); } - } else { - goto cannot_assign; + return; } - } else { - goto cannot_assign; } - return; - -cannot_assign: compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression"); } @@ -1941,51 +1936,52 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { } } else { plain_assign: - if (MICROPY_COMP_DOUBLE_TUPLE_ASSIGN - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 2 - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 2) { - // optimisation for a, b = c, d - mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1]; + #if MICROPY_COMP_DOUBLE_TUPLE_ASSIGN + if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) + && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)) { mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; - if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) - || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)) { - // can't optimise when it's a star expression on the lhs - goto no_optimisation; + pns1 = (mp_parse_node_struct_t*)pns->nodes[1]; + uint32_t n_pns0 = MP_PARSE_NODE_STRUCT_NUM_NODES(pns0); + // Can only optimise a tuple-to-tuple assignment when all of the following hold: + // - equal number of items in LHS and RHS tuples + // - 2 or 3 items in the tuples + // - there are no star expressions in the LHS tuple + if (n_pns0 == MP_PARSE_NODE_STRUCT_NUM_NODES(pns1) + && (n_pns0 == 2 + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + || n_pns0 == 3 + #endif + ) + && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) + && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + && (n_pns0 == 2 || !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) + #endif + ) { + // Optimisation for a, b = c, d or a, b, c = d, e, f + compile_node(comp, pns1->nodes[0]); // rhs + compile_node(comp, pns1->nodes[1]); // rhs + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + if (n_pns0 == 3) { + compile_node(comp, pns1->nodes[2]); // rhs + EMIT(rot_three); + } + #endif + EMIT(rot_two); + c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store + c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store + #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN + if (n_pns0 == 3) { + c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store + } + #endif + return; } - compile_node(comp, pns10->nodes[0]); // rhs - compile_node(comp, pns10->nodes[1]); // rhs - EMIT(rot_two); - c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store - c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store - } else if (MICROPY_COMP_TRIPLE_TUPLE_ASSIGN - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr) - && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr) - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 3 - && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 3) { - // optimisation for a, b, c = d, e, f - mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1]; - mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; - if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) - || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) - || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) { - // can't optimise when it's a star expression on the lhs - goto no_optimisation; - } - compile_node(comp, pns10->nodes[0]); // rhs - compile_node(comp, pns10->nodes[1]); // rhs - compile_node(comp, pns10->nodes[2]); // rhs - EMIT(rot_three); - EMIT(rot_two); - c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store - c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store - c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store - } else { - no_optimisation: - compile_node(comp, pns->nodes[1]); // rhs - c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store } + #endif + + compile_node(comp, pns->nodes[1]); // rhs + c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store } } else { goto plain_assign; diff --git a/py/emitbc.c b/py/emitbc.c index 5e7fa623a..32e833000 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -437,7 +437,9 @@ void mp_emit_bc_end_pass(emit_t *emit) { } else if (emit->pass == MP_PASS_EMIT) { mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS emit->code_info_size + emit->bytecode_size, + #endif emit->const_table, #if MICROPY_PERSISTENT_CODE_SAVE emit->ct_cur_obj, emit->ct_cur_raw_code, diff --git a/py/emitglue.c b/py/emitglue.c index d2add988f..74bf8ddca 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 f2a48c5e5..0830a0d5c 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -63,7 +63,10 @@ typedef struct _mp_raw_code_t { mp_raw_code_t *mp_emit_glue_new_raw_code(void); -void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t len, +void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + size_t len, + #endif const mp_uint_t *const_table, #if MICROPY_PERSISTENT_CODE_SAVE uint16_t n_obj, uint16_t n_raw_code, diff --git a/py/formatfloat.c b/py/formatfloat.c index 4228f99ff..dc7fc1d1f 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 5196954e2..84c9918fd 100644 --- a/py/gc.c +++ b/py/gc.c @@ -203,29 +203,14 @@ bool gc_is_locked(void) { #endif #endif -// ptr should be of type void* -#define VERIFY_MARK_AND_PUSH(ptr) \ - do { \ - if (VERIFY_PTR(ptr)) { \ - size_t _block = BLOCK_FROM_PTR(ptr); \ - if (ATB_GET_KIND(_block) == AT_HEAD) { \ - /* an unmarked head, mark it, and push it on gc stack */ \ - TRACE_MARK(_block, ptr); \ - ATB_HEAD_TO_MARK(_block); \ - if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { \ - *MP_STATE_MEM(gc_sp)++ = _block; \ - } else { \ - MP_STATE_MEM(gc_stack_overflow) = 1; \ - } \ - } \ - } \ - } while (0) - -STATIC void gc_drain_stack(void) { - while (MP_STATE_MEM(gc_sp) > MP_STATE_MEM(gc_stack)) { - // pop the next block off the stack - size_t block = *--MP_STATE_MEM(gc_sp); - +// Take the given block as the topmost block on the stack. Check all it's +// children: mark the unmarked child blocks and put those newly marked +// blocks on the stack. When all children have been checked, pop off the +// topmost block on the stack and repeat with that one. +STATIC void gc_mark_subtree(size_t block) { + // Start with the block passed in the argument. + size_t sp = 0; + for (;;) { // work out number of consecutive blocks in the chain starting with this one size_t n_blocks = 0; do { @@ -236,22 +221,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); } } } @@ -319,7 +323,6 @@ void gc_collect_start(void) { MP_STATE_MEM(gc_alloc_amount) = 0; #endif MP_STATE_MEM(gc_stack_overflow) = 0; - MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack); // Trace root pointers. This relies on the root pointers being organised // correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals, @@ -337,8 +340,15 @@ void gc_collect_start(void) { void gc_collect_root(void **ptrs, size_t len) { for (size_t i = 0; i < len; i++) { void *ptr = ptrs[i]; - VERIFY_MARK_AND_PUSH(ptr); - gc_drain_stack(); + if (VERIFY_PTR(ptr)) { + 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); + } + } } } diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index 525dec197..176440136 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -24,12 +24,16 @@ def write_out(fname, output): f.write("\n".join(output) + "\n") def process_file(f): + re_line = re.compile(r"#[line]*\s\d+\s\"([^\"]+)\"") + re_qstr = re.compile(r'MP_QSTR_[_a-zA-Z0-9]+') output = [] last_fname = None for line in f: + if line.isspace(): + continue # match gcc-like output (# n "file") and msvc-like output (#line n "file") - if line and (line[0:2] == "# " or line[0:5] == "#line"): - m = re.match(r"#[line]*\s\d+\s\"([^\"]+)\"", line) + if line.startswith(('# ', '#line')): + m = re_line.match(line) assert m is not None fname = m.group(1) if not fname.endswith(".c"): @@ -39,7 +43,7 @@ def process_file(f): output = [] last_fname = fname continue - for match in re.findall(r'MP_QSTR_[_a-zA-Z0-9]+', line): + for match in re_qstr.findall(line): name = match.replace('MP_QSTR_', '') if name not in QSTRING_BLACK_LIST: output.append('Q(' + name + ')') diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py index 749160b4d..aedc292e4 100644 --- a/py/makeversionhdr.py +++ b/py/makeversionhdr.py @@ -99,7 +99,7 @@ def make_version_header(filename): # Only write the file if we need to if write_file: - print("Generating %s" % filename) + print("GEN %s" % filename) with open(filename, 'w') as f: f.write(file_data) diff --git a/py/misc.h b/py/misc.h index 5d557db6f..72560da1e 100644 --- a/py/misc.h +++ b/py/misc.h @@ -121,8 +121,15 @@ typedef uint32_t unichar; typedef uint unichar; #endif +#if MICROPY_PY_BUILTINS_STR_UNICODE unichar utf8_get_char(const byte *s); const byte *utf8_next_char(const byte *s); +size_t utf8_charlen(const byte *str, size_t len); +#else +static inline unichar utf8_get_char(const byte *s) { return *s; } +static inline const byte *utf8_next_char(const byte *s) { return s + 1; } +static inline size_t utf8_charlen(const byte *str, size_t len) { (void)str; return len; } +#endif bool unichar_isspace(unichar c); bool unichar_isalpha(unichar c); @@ -135,7 +142,6 @@ bool unichar_islower(unichar c); unichar unichar_tolower(unichar c); unichar unichar_toupper(unichar c); mp_uint_t unichar_xdigit_value(unichar c); -mp_uint_t unichar_charlen(const char *str, mp_uint_t len); #define UTF8_IS_NONASCII(ch) ((ch) & 0x80) #define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80) @@ -198,20 +204,6 @@ int DEBUG_printf(const char *fmt, ...); extern mp_uint_t mp_verbose_flag; -// This is useful for unicode handling. Some CPU archs has -// special instructions for efficient implementation of this -// function (e.g. CLZ on ARM). -// NOTE: this function is unused at the moment -#ifndef count_lead_ones -static inline mp_uint_t count_lead_ones(byte val) { - mp_uint_t c = 0; - for (byte mask = 0x80; val & mask; mask >>= 1) { - c++; - } - return c; -} -#endif - /** float internals *************/ #if MICROPY_PY_BUILTINS_FLOAT diff --git a/py/mkrules.mk b/py/mkrules.mk index 96f6e35a6..fa7138695 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -97,7 +97,7 @@ $(HEADER_BUILD): ifneq ($(FROZEN_DIR),) $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DEPS) - $(ECHO) "Generating $@" + $(ECHO) "GEN $@" $(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@ endif @@ -118,7 +118,7 @@ $(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py $(TOP)/mpy-cross/mpy-cross # to build frozen_mpy.c from all .mpy files $(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h - @$(ECHO) "Creating $@" + @$(ECHO) "GEN $@" $(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif diff --git a/py/modbuiltins.c b/py/modbuiltins.c index c8e3235f6..5d4ec8ffe 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -137,7 +137,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable); STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { #if MICROPY_PY_BUILTINS_STR_UNICODE mp_uint_t c = mp_obj_get_int(o_in); - char str[4]; + uint8_t str[4]; int len = 0; if (c < 0x80) { *str = c; len = 1; @@ -159,12 +159,12 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { } else { mp_raise_ValueError("chr() arg not in range(0x110000)"); } - return mp_obj_new_str_via_qstr(str, len); + return mp_obj_new_str_via_qstr((char*)str, len); #else mp_int_t ord = mp_obj_get_int(o_in); if (0 <= ord && ord <= 0xff) { - char str[1] = {ord}; - return mp_obj_new_str_via_qstr(str, 1); + uint8_t str[1] = {ord}; + return mp_obj_new_str_via_qstr((char*)str, 1); } else { mp_raise_ValueError("chr() arg not in range(256)"); } @@ -173,46 +173,24 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr); STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) { - // TODO make this function more general and less of a hack - - mp_obj_dict_t *dict = NULL; - mp_map_t *members = NULL; - if (n_args == 0) { - // make a list of names in the local name space - dict = mp_locals_get(); - } else { // n_args == 1 - // make a list of names in the given object - if (MP_OBJ_IS_TYPE(args[0], &mp_type_module)) { - dict = mp_obj_module_get_globals(args[0]); - } else { - mp_obj_type_t *type; - if (MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { - type = MP_OBJ_TO_PTR(args[0]); - } else { - type = mp_obj_get_type(args[0]); - } - if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) { - dict = type->locals_dict; - } - } - if (mp_obj_is_instance_type(mp_obj_get_type(args[0]))) { - mp_obj_instance_t *inst = MP_OBJ_TO_PTR(args[0]); - members = &inst->members; - } - } - mp_obj_t dir = mp_obj_new_list(0, NULL); - if (dict != NULL) { + if (n_args == 0) { + // Make a list of names in the local namespace + mp_obj_dict_t *dict = mp_locals_get(); for (size_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { mp_obj_list_append(dir, dict->map.table[i].key); } } - } - if (members != NULL) { - for (size_t i = 0; i < members->alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(members, i)) { - mp_obj_list_append(dir, members->table[i].key); + } else { // n_args == 1 + // Make a list of names in the given object + // Implemented by probing all possible qstrs with mp_load_method_maybe + size_t nqstr = QSTR_TOTAL(); + for (size_t i = 1; i < nqstr; ++i) { + mp_obj_t dest[2]; + mp_load_method_maybe(args[0], i, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_obj_list_append(dir, MP_OBJ_NEW_QSTR(i)); } } } @@ -343,19 +321,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]); } } diff --git a/py/modcollections.c b/py/modcollections.c index 1a1560387..bb6488471 100644 --- a/py/modcollections.c +++ b/py/modcollections.c @@ -30,6 +30,9 @@ STATIC const mp_rom_map_elem_t mp_module_collections_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucollections) }, + #if MICROPY_PY_COLLECTIONS_DEQUE + { MP_ROM_QSTR(MP_QSTR_deque), MP_ROM_PTR(&mp_type_deque) }, + #endif { MP_ROM_QSTR(MP_QSTR_namedtuple), MP_ROM_PTR(&mp_namedtuple_obj) }, #if MICROPY_PY_COLLECTIONS_ORDEREDDICT { MP_ROM_QSTR(MP_QSTR_OrderedDict), MP_ROM_PTR(&mp_type_ordereddict) }, diff --git a/py/modmicropython.c b/py/modmicropython.c index c14a0177d..5cc7bdbe2 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -103,15 +103,15 @@ STATIC mp_obj_t mp_micropython_qstr_info(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_qstr_info_obj, 0, 1, mp_micropython_qstr_info); -#if MICROPY_STACK_CHECK +#endif // MICROPY_PY_MICROPYTHON_MEM_INFO + +#if MICROPY_PY_MICROPYTHON_STACK_USE STATIC mp_obj_t mp_micropython_stack_use(void) { return MP_OBJ_NEW_SMALL_INT(mp_stack_usage()); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_stack_use_obj, mp_micropython_stack_use); #endif -#endif // MICROPY_PY_MICROPYTHON_MEM_INFO - #if MICROPY_ENABLE_PYSTACK STATIC mp_obj_t mp_micropython_pystack_use(void) { return MP_OBJ_NEW_SMALL_INT(mp_pystack_usage()); @@ -167,10 +167,10 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { #endif { MP_ROM_QSTR(MP_QSTR_mem_info), MP_ROM_PTR(&mp_micropython_mem_info_obj) }, { MP_ROM_QSTR(MP_QSTR_qstr_info), MP_ROM_PTR(&mp_micropython_qstr_info_obj) }, - #if MICROPY_STACK_CHECK +#endif + #if MICROPY_PY_MICROPYTHON_STACK_USE { MP_ROM_QSTR(MP_QSTR_stack_use), MP_ROM_PTR(&mp_micropython_stack_use_obj) }, #endif -#endif #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0) { MP_ROM_QSTR(MP_QSTR_alloc_emergency_exception_buf), MP_ROM_PTR(&mp_alloc_emergency_exception_buf_obj) }, #endif diff --git a/py/mpconfig.h b/py/mpconfig.h index 763bb378e..532b54ab0 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -347,7 +347,7 @@ #endif // Whether to enable optimisation of: a, b, c = d, e, f -// Cost 156 bytes (Thumb2) +// Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2) #ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0) #endif @@ -405,6 +405,13 @@ /*****************************************************************************/ /* Python internal features */ +// Whether to enable import of external modules +// When disabled, only importing of built-in modules is supported +// When enabled, a port must implement mp_import_stat (among other things) +#ifndef MICROPY_ENABLE_EXTERNAL_IMPORT +#define MICROPY_ENABLE_EXTERNAL_IMPORT (1) +#endif + // Whether to use the POSIX reader for importing files #ifndef MICROPY_READER_POSIX #define MICROPY_READER_POSIX (0) @@ -787,6 +794,14 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) #endif +// Whether to support binary ops [only (in)equality is defined] between range +// objects. With this option disabled all range objects that are not exactly +// the same object will compare as not-equal. With it enabled the semantics +// match CPython and ranges are equal if they yield the same sequence of items. +#ifndef MICROPY_PY_BUILTINS_RANGE_BINOP +#define MICROPY_PY_BUILTINS_RANGE_BINOP (0) +#endif + // Whether to support timeout exceptions (like socket.timeout) #ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR #define MICROPY_PY_BUILTINS_TIMEOUTERROR (0) @@ -892,6 +907,11 @@ typedef double mp_float_t; #define MICROPY_PY_MICROPYTHON_MEM_INFO (0) #endif +// Whether to provide "micropython.stack_use" function +#ifndef MICROPY_PY_MICROPYTHON_STACK_USE +#define MICROPY_PY_MICROPYTHON_STACK_USE (MICROPY_PY_MICROPYTHON_MEM_INFO) +#endif + // Whether to provide "array" module. Note that large chunk of the // underlying code is shared with "bytearray" builtin type, so to // get real savings, it should be disabled too. @@ -916,6 +936,11 @@ typedef double mp_float_t; #define MICROPY_PY_COLLECTIONS (1) #endif +// Whether to provide "ucollections.deque" type +#ifndef MICROPY_PY_COLLECTIONS_DEQUE +#define MICROPY_PY_COLLECTIONS_DEQUE (0) +#endif + // Whether to provide "collections.OrderedDict" type #ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT #define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0) diff --git a/py/mpstate.h b/py/mpstate.h index 45e89590f..816698f4e 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -78,7 +78,6 @@ typedef struct _mp_state_mem_t { int gc_stack_overflow; size_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE]; - size_t *gc_sp; uint16_t gc_lock_depth; // This variable controls auto garbage collection. If set to 0 then the @@ -167,6 +166,10 @@ typedef struct _mp_state_vm_t { // root pointers for extmod + #if MICROPY_REPL_EVENT_DRIVEN + vstr_t *repl_line; + #endif + #if MICROPY_PY_OS_DUPTERM mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM]; mp_obj_t dupterm_arr_obj; diff --git a/py/mpz.c b/py/mpz.c index 018a5454f..fa5086862 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; @@ -1434,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; @@ -1673,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 e2d0c30aa..3c36cac66 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/nlr.c b/py/nlr.c index e4d6d10c0..03d01577e 100644 --- a/py/nlr.c +++ b/py/nlr.c @@ -26,18 +26,9 @@ #include "py/mpstate.h" -// Helper macros to save/restore the pystack state -#if MICROPY_ENABLE_PYSTACK -#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) -#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack -#else -#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf -#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf -#endif - #if !MICROPY_NLR_SETJMP // When not using setjmp, nlr_push_tail is called from inline asm so needs special care -#if MICROPY_NLR_X86 && (defined(_WIN32) || defined(__CYGWIN__)) +#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 @@ -58,17 +49,3 @@ void nlr_pop(void) { nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); *top = (*top)->prev; } - -NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; - - nlr_jump_tail(top); -} diff --git a/py/nlr.h b/py/nlr.h index 012a73c31..90595a12d 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -35,15 +35,20 @@ #include "py/mpconfig.h" // If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch -// Allow a port to set MICROPY_NLR_NUM_REGS to define their own implementation -#if !MICROPY_NLR_SETJMP && !defined(MICROPY_NLR_NUM_REGS) +#if !MICROPY_NLR_SETJMP +// A lot of nlr-related things need different treatment on Windows +#if defined(_WIN32) || defined(__CYGWIN__) +#define MICROPY_NLR_OS_WINDOWS 1 +#else +#define MICROPY_NLR_OS_WINDOWS 0 +#endif #if defined(__i386__) #define MICROPY_NLR_X86 (1) #define MICROPY_NLR_NUM_REGS (6) #elif defined(__x86_64__) #define MICROPY_NLR_X64 (1) - #if defined(__CYGWIN__) - #define MICROPY_NLR_NUM_REGS (12) + #if MICROPY_NLR_OS_WINDOWS + #define MICROPY_NLR_NUM_REGS (10) #else #define MICROPY_NLR_NUM_REGS (8) #endif @@ -80,6 +85,26 @@ struct _nlr_buf_t { #endif }; +// Helper macros to save/restore the pystack state +#if MICROPY_ENABLE_PYSTACK +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack +#else +#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf +#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf +#endif + +// 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." @@ -92,7 +117,6 @@ unsigned int nlr_push(nlr_buf_t *); unsigned int nlr_push_tail(nlr_buf_t *top); void nlr_pop(void); NORETURN void nlr_jump(void *val); -NORETURN void nlr_jump_tail(nlr_buf_t *top); // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c index 6ddad3793..960dd86f5 100644 --- a/py/nlrsetjmp.c +++ b/py/nlrsetjmp.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,11 +24,19 @@ * THE SOFTWARE. */ -#include "py/nlr.h" +#include "py/mpstate.h" #if MICROPY_NLR_SETJMP -NORETURN void nlr_jump_tail(nlr_buf_t *top) { +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 4edd1456d..7dbeac1b6 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 @@ -37,6 +37,7 @@ // r4-r11, r13=sp __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { + __asm volatile ( "str r4, [r0, #12] \n" // store r4 into nlr_buf "str r5, [r0, #16] \n" // store r5 into nlr_buf @@ -74,10 +75,18 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { "b nlr_push_tail \n" // do the rest in C #endif ); + + #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) + // Older versions of gcc give an error when naked functions don't return a value + return 0; + #endif } -NORETURN __attribute__((naked)) void nlr_jump_tail(nlr_buf_t *top) { +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + __asm volatile ( + "mov r0, %0 \n" // r0 points to nlr_buf "ldr r4, [r0, #12] \n" // load r4 from nlr_buf "ldr r5, [r0, #16] \n" // load r5 from nlr_buf "ldr r6, [r0, #20] \n" // load r6 from nlr_buf @@ -106,7 +115,16 @@ NORETURN __attribute__((naked)) void nlr_jump_tail(nlr_buf_t *top) { #endif "movs r0, #1 \n" // return 1, non-local return "bx lr \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers ); + + #if defined(__GNUC__) + __builtin_unreachable(); + #else + for (;;); // needed to silence compiler warning + #endif } #endif // MICROPY_NLR_THUMB diff --git a/py/nlrx64.c b/py/nlrx64.c index e7e2e1474..a3a1cf341 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -33,16 +33,12 @@ // x86-64 callee-save registers are: // rbx, rbp, rsp, r12, r13, r14, r15 -#if defined(_WIN32) || defined(__CYGWIN__) -#define NLR_OS_WINDOWS 1 -#else -#define NLR_OS_WINDOWS 0 -#endif +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; - #if NLR_OS_WINDOWS + #if MICROPY_NLR_OS_WINDOWS __asm volatile ( "movq (%rsp), %rax \n" // load return %rip @@ -86,35 +82,30 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -NORETURN void nlr_jump_tail(nlr_buf_t *top) { - (void)top; +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( - #if NLR_OS_WINDOWS - "movq 88(%rcx), %rsi \n" // load saved %rsi - "movq 80(%rcx), %rdi \n" // load saved %rdr - "movq 72(%rcx), %r15 \n" // load saved %r15 - "movq 64(%rcx), %r14 \n" // load saved %r14 - "movq 56(%rcx), %r13 \n" // load saved %r13 - "movq 48(%rcx), %r12 \n" // load saved %r12 - "movq 40(%rcx), %rbx \n" // load saved %rbx - "movq 32(%rcx), %rsp \n" // load saved %rsp - "movq 24(%rcx), %rbp \n" // load saved %rbp - "movq 16(%rcx), %rax \n" // load saved %rip - #else - "movq 72(%rdi), %r15 \n" // load saved %r15 - "movq 64(%rdi), %r14 \n" // load saved %r14 - "movq 56(%rdi), %r13 \n" // load saved %r13 - "movq 48(%rdi), %r12 \n" // load saved %r12 - "movq 40(%rdi), %rbx \n" // load saved %rbx - "movq 32(%rdi), %rsp \n" // load saved %rsp - "movq 24(%rdi), %rbp \n" // load saved %rbp - "movq 16(%rdi), %rax \n" // load saved %rip + "movq %0, %%rcx \n" // %rcx points to nlr_buf + #if MICROPY_NLR_OS_WINDOWS + "movq 88(%%rcx), %%rsi \n" // load saved %rsi + "movq 80(%%rcx), %%rdi \n" // load saved %rdr #endif - "movq %rax, (%rsp) \n" // store saved %rip to stack - "xorq %rax, %rax \n" // clear return register - "inc %al \n" // increase to make 1, non-local return + "movq 72(%%rcx), %%r15 \n" // load saved %r15 + "movq 64(%%rcx), %%r14 \n" // load saved %r14 + "movq 56(%%rcx), %%r13 \n" // load saved %r13 + "movq 48(%%rcx), %%r12 \n" // load saved %r12 + "movq 40(%%rcx), %%rbx \n" // load saved %rbx + "movq 32(%%rcx), %%rsp \n" // load saved %rsp + "movq 24(%%rcx), %%rbp \n" // load saved %rbp + "movq 16(%%rcx), %%rax \n" // load saved %rip + "movq %%rax, (%%rsp) \n" // store saved %rip to stack + "xorq %%rax, %%rax \n" // clear return register + "inc %%al \n" // increase to make 1, non-local return "ret \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers ); for (;;); // needed to silence compiler warning diff --git a/py/nlrx86.c b/py/nlrx86.c index cc37f72af..23882cc30 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -33,6 +33,12 @@ // For reference, x86 callee save regs are: // ebx, esi, edi, ebp, esp, eip +#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 + unsigned int nlr_push(nlr_buf_t *nlr) { (void)nlr; @@ -58,20 +64,24 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -NORETURN void nlr_jump_tail(nlr_buf_t *top) { - (void)top; +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( - "mov 28(%edx), %esi \n" // load saved %esi - "mov 24(%edx), %edi \n" // load saved %edi - "mov 20(%edx), %ebx \n" // load saved %ebx - "mov 16(%edx), %esp \n" // load saved %esp - "mov 12(%edx), %ebp \n" // load saved %ebp - "mov 8(%edx), %eax \n" // load saved %eip - "mov %eax, (%esp) \n" // store saved %eip to stack - "xor %eax, %eax \n" // clear return register - "inc %al \n" // increase to make 1, non-local return + "mov %0, %%edx \n" // %edx points to nlr_buf + "mov 28(%%edx), %%esi \n" // load saved %esi + "mov 24(%%edx), %%edi \n" // load saved %edi + "mov 20(%%edx), %%ebx \n" // load saved %ebx + "mov 16(%%edx), %%esp \n" // load saved %esp + "mov 12(%%edx), %%ebp \n" // load saved %ebp + "mov 8(%%edx), %%eax \n" // load saved %eip + "mov %%eax, (%%esp) \n" // store saved %eip to stack + "xor %%eax, %%eax \n" // clear return register + "inc %%al \n" // increase to make 1, non-local return "ret \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers ); for (;;); // needed to silence compiler warning diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index 6b9918227..cd3dee364 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -37,7 +37,6 @@ // a3-a7 = rest of args unsigned int nlr_push(nlr_buf_t *nlr) { - (void)nlr; __asm volatile ( "s32i.n a0, a2, 8 \n" // save regs... @@ -56,10 +55,11 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -NORETURN void nlr_jump_tail(nlr_buf_t *top) { - (void)top; +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( + "mov.n a2, %0 \n" // a2 points to nlr_buf "l32i.n a0, a2, 8 \n" // restore regs... "l32i.n a1, a2, 12 \n" "l32i.n a8, a2, 16 \n" @@ -72,6 +72,9 @@ NORETURN void nlr_jump_tail(nlr_buf_t *top) { "l32i.n a15, a2, 44 \n" "movi.n a2, 1 \n" // return 1, non-local return "ret.n \n" // return + : // output operands + : "r"(top) // input operands + : // clobbered registers ); for (;;); // needed to silence compiler warning diff --git a/py/obj.h b/py/obj.h index 10cb48961..2779b3f86 100644 --- a/py/obj.h +++ b/py/obj.h @@ -250,6 +250,8 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; // The macros below are derived from the ones above and are used to // check for more specific object types. +// Note: these are kept as macros because inline functions sometimes use much +// more code space than the equivalent macros, depending on the compiler. #define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that #define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)) @@ -257,17 +259,6 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; #define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op)) #define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function)) -// Note: inline functions sometimes use much more code space than the -// equivalent macros, depending on the compiler. -//static inline bool MP_OBJ_IS_TYPE(mp_const_obj_t o, const mp_obj_type_t *t) { return (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))); } // this does not work for checking a string, use below macro for that -//static inline bool MP_OBJ_IS_INT(mp_const_obj_t o) { return (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)); } // returns true if o is a small int or long int -// Need to forward declare these for the inline function to compile. -extern const mp_obj_type_t mp_type_int; -extern const mp_obj_type_t mp_type_bool; -static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int -//static inline bool MP_OBJ_IS_STR(mp_const_obj_t o) { return (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)); } - - // These macros are used to declare and define constant function objects // You can put "static" in front of the definitions to make them local @@ -553,6 +544,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; @@ -624,7 +616,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 @@ -681,6 +672,7 @@ bool mp_obj_is_true(mp_obj_t arg); bool mp_obj_is_callable(mp_obj_t o_in); bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2); +static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int mp_int_t mp_obj_get_int(mp_const_obj_t arg); mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg); bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value); @@ -752,8 +744,6 @@ void mp_obj_tuple_del(mp_obj_t self_in); mp_int_t mp_obj_tuple_hash(mp_obj_t self_in); // list -struct _mp_obj_list_t; -void mp_obj_list_init(struct _mp_obj_list_t *o, size_t n); mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value); void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items); diff --git a/py/objdeque.c b/py/objdeque.c new file mode 100644 index 000000000..bbb078103 --- /dev/null +++ b/py/objdeque.c @@ -0,0 +1,166 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpconfig.h" +#if MICROPY_PY_COLLECTIONS_DEQUE + +#include "py/runtime.h" + +typedef struct _mp_obj_deque_t { + mp_obj_base_t base; + size_t alloc; + size_t i_get; + size_t i_put; + mp_obj_t *items; + uint32_t flags; + #define FLAG_CHECK_OVERFLOW 1 +} mp_obj_deque_t; + +STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 3, false); + + /* Initialization from existing sequence is not supported, so an empty + tuple must be passed as such. */ + if (args[0] != mp_const_empty_tuple) { + mp_raise_ValueError(NULL); + } + + // 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: { + mp_int_t len = self->i_put - self->i_get; + if (len < 0) { + len += self->alloc; + } + return MP_OBJ_NEW_SMALL_INT(len); + } + #if MICROPY_PY_SYS_GETSIZEOF + case MP_UNARY_OP_SIZEOF: { + size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc; + return MP_OBJ_NEW_SMALL_INT(sz); + } + #endif + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + + size_t new_i_put = self->i_put + 1; + if (new_i_put == self->alloc) { + new_i_put = 0; + } + + if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) { + mp_raise_msg(&mp_type_IndexError, "full"); + } + + self->items[self->i_put] = arg; + self->i_put = new_i_put; + + if (self->i_get == new_i_put) { + if (++self->i_get == self->alloc) { + self->i_get = 0; + } + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append); + +STATIC mp_obj_t deque_popleft(mp_obj_t self_in) { + mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->i_get == self->i_put) { + mp_raise_msg(&mp_type_IndexError, "empty"); + } + + mp_obj_t ret = self->items[self->i_get]; + self->items[self->i_get] = MP_OBJ_NULL; + + if (++self->i_get == self->alloc) { + self->i_get = 0; + } + + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft); + +#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 f6fb594b3..c0647067a 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -195,9 +195,16 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { /******************************************************************************/ /* dict methods */ +STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) { + if (dict->map.is_fixed) { + mp_raise_TypeError(NULL); + } +} + STATIC mp_obj_t dict_clear(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); mp_map_clear(&self->map); @@ -253,6 +260,9 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromk STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) { mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); + if (lookup_kind != MP_MAP_LOOKUP) { + mp_ensure_not_fixed(self); + } mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind); mp_obj_t value; if (elem == NULL || elem->value == MP_OBJ_NULL) { @@ -295,6 +305,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setde STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); size_t cur = 0; mp_map_elem_t *next = dict_iter_next(self, &cur); if (next == NULL) { @@ -313,6 +324,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem); STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); + mp_ensure_not_fixed(self); mp_arg_check_num(n_args, kwargs->used, 1, 2, true); @@ -578,6 +590,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) { mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); + mp_ensure_not_fixed(self); mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; return self_in; } diff --git a/py/objexcept.c b/py/objexcept.c index 524f105ce..1e746bc81 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; @@ -189,7 +186,7 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) { } } -STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] != MP_OBJ_NULL) { // store/delete attribute @@ -217,17 +214,7 @@ const mp_obj_type_t mp_type_BaseException = { .name = MP_QSTR_BaseException, .print = mp_obj_exception_print, .make_new = mp_obj_exception_make_new, - .attr = exception_attr, -}; - -#define MP_DEFINE_EXCEPTION(exc_name, base_name) \ -const mp_obj_type_t mp_type_ ## exc_name = { \ - { &mp_type_type }, \ - .name = MP_QSTR_ ## exc_name, \ - .print = mp_obj_exception_print, \ - .make_new = mp_obj_exception_make_new, \ - .attr = exception_attr, \ - .parent = &mp_type_ ## base_name, \ + .attr = mp_obj_exception_attr, }; // List of all exceptions, arranged as in the table at: diff --git a/py/objexcept.h b/py/objexcept.h index f67651a7e..7c3076224 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 75212a4d2..e4d5a6570 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -293,7 +293,7 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t break; case MP_BINARY_OP_POWER: case MP_BINARY_OP_INPLACE_POWER: - if (lhs_val == 0 && rhs_val < 0) { + if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) { goto zero_division_error; } if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val)) { diff --git a/py/objint.c b/py/objint.c index 4f2e610a5..270e16969 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/objlist.h b/py/objlist.h index 28b5495a9..a43663db7 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 f9363e379..c4aba3a7b 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -247,17 +247,7 @@ mp_obj_t mp_module_get(qstr module_name) { if (el == NULL) { return MP_OBJ_NULL; } - - if (MICROPY_MODULE_BUILTIN_INIT) { - // look for __init__ and call it if it exists - mp_obj_t dest[2]; - mp_load_method_maybe(el->value, MP_QSTR___init__, dest); - if (dest[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, dest); - // register module so __init__ is not called again - mp_module_register(module_name, el->value); - } - } + mp_module_call_init(module_name, el->value); } // module found, return it @@ -268,3 +258,19 @@ void mp_module_register(qstr qst, mp_obj_t module) { mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map; mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module; } + +#if MICROPY_MODULE_BUILTIN_INIT +void mp_module_call_init(qstr module_name, mp_obj_t module_obj) { + // Look for __init__ and call it if it exists + mp_obj_t dest[2]; + mp_load_method_maybe(module_obj, MP_QSTR___init__, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, dest); + // Register module so __init__ is not called again. + // If a module can be referenced by more than one name (eg due to weak links) + // then __init__ will still be called for each distinct import, and it's then + // up to the particular module to make sure it's __init__ code only runs once. + mp_module_register(module_name, module_obj); + } +} +#endif diff --git a/py/objmodule.h b/py/objmodule.h index b5c07dc33..b7702ec50 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/objrange.c b/py/objrange.c index 3874adb11..86aa0ccfe 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/objstr.c b/py/objstr.c index 30153813d..c42f38e75 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -223,7 +223,10 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size } if (MP_OBJ_IS_SMALL_INT(args[0])) { - uint len = MP_OBJ_SMALL_INT_VALUE(args[0]); + mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]); + if (len < 0) { + mp_raise_ValueError(NULL); + } vstr_t vstr; vstr_init_len(&vstr, len); memset(vstr.buf, 0, len); @@ -660,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 @@ -1704,7 +1705,7 @@ STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { // if needle_len is zero then we count each gap between characters as an occurrence if (needle_len == 0) { - return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char*)start, end - start) + 1); + return MP_OBJ_NEW_SMALL_INT(utf8_charlen(start, end - start) + 1); } // count the occurrences diff --git a/py/objstrunicode.c b/py/objstrunicode.c index a1f54b8a2..badb569d7 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -104,7 +104,7 @@ STATIC mp_obj_t uni_unary_op(mp_unary_op_t op, mp_obj_t self_in) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(str_len != 0); case MP_UNARY_OP_LEN: - return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char *)str_data, str_len)); + return MP_OBJ_NEW_SMALL_INT(utf8_charlen(str_data, str_len)); default: return MP_OBJ_NULL; // op not supported } diff --git a/py/objtype.c b/py/objtype.c index 33757287a..7df349ce9 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -975,21 +975,21 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (self->locals_dict != NULL) { assert(self->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now mp_map_t *locals_map = &self->locals_dict->map; + if (locals_map->is_fixed) { + // can't apply delete/store to a fixed map + return; + } if (dest[1] == MP_OBJ_NULL) { // delete attribute mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); - // note that locals_map may be in ROM, so remove will fail in that case if (elem != NULL) { dest[0] = MP_OBJ_NULL; // indicate success } } else { // store attribute mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); - // note that locals_map may be in ROM, so add will fail in that case - if (elem != NULL) { - elem->value = dest[1]; - dest[0] = MP_OBJ_NULL; // indicate success - } + elem->value = dest[1]; + dest[0] = MP_OBJ_NULL; // indicate success } } } diff --git a/py/parse.c b/py/parse.c index b80cc8fb1..8c1286492 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,6 +241,14 @@ typedef struct _parser_t { #endif } parser_t; +STATIC const uint16_t *get_rule_arg(uint8_t r_id) { + size_t off = rule_arg_offset_table[r_id]; + if (r_id >= FIRST_RULE_WITH_OFFSET_ABOVE_255) { + off |= 0x100; + } + return &rule_arg_combined_table[off]; +} + STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) { // use a custom memory allocator to store parse nodes sequentially in large chunks @@ -205,7 +290,7 @@ STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) { return ret; } -STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t arg_i) { +STATIC void push_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t arg_i) { if (parser->rule_stack_top >= parser->rule_stack_alloc) { rule_stack_t *rs = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC); parser->rule_stack = rs; @@ -213,21 +298,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) { @@ -313,11 +399,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); } @@ -381,7 +467,7 @@ STATIC mp_parse_node_t mp_parse_node_new_small_int_checked(parser_t *parser, mp_ return mp_parse_node_new_small_int(val); } -STATIC void push_result_token(parser_t *parser, const rule_t *rule) { +STATIC void push_result_token(parser_t *parser, uint8_t rule_id) { mp_parse_node_t pn; mp_lexer_t *lex = parser->lexer; if (lex->tok_kind == MP_TOKEN_NAME) { @@ -389,7 +475,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { #if MICROPY_COMP_CONST // if name is a standalone identifier, look it up in the table of dynamic constants mp_map_elem_t *elem; - if (rule->rule_id == RULE_atom + if (rule_id == RULE_atom && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) { if (MP_OBJ_IS_SMALL_INT(elem->value)) { pn = mp_parse_node_new_small_int_checked(parser, elem->value); @@ -400,7 +486,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) { pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); } #else - (void)rule; + (void)rule_id; pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id); #endif } else if (lex->tok_kind == MP_TOKEN_INTEGER) { @@ -454,12 +540,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;) { @@ -469,7 +555,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; @@ -496,7 +582,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)) { @@ -514,23 +600,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; @@ -543,9 +629,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)) { @@ -589,7 +675,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)) { @@ -608,7 +694,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) @@ -647,7 +733,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; } @@ -663,7 +749,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) @@ -708,9 +794,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)) { @@ -724,11 +810,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; } @@ -736,7 +822,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); } @@ -773,14 +859,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: @@ -788,19 +871,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; @@ -808,19 +896,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; } } @@ -832,7 +920,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; @@ -849,13 +937,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 { @@ -870,8 +958,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; } } @@ -882,7 +970,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)) { @@ -891,7 +979,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; } } @@ -902,8 +990,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; @@ -918,7 +1006,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) { @@ -931,19 +1019,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)* @@ -981,13 +1069,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 @@ -1000,7 +1088,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; } @@ -1010,7 +1098,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; } @@ -1019,12 +1107,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 98e773685..124489c66 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -172,10 +172,15 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool #if MICROPY_PY_BUILTINS_FLOAT // DEC_VAL_MAX only needs to be rough and is used to retain precision while not overflowing +// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #define DEC_VAL_MAX 1e20F +#define SMALL_NORMAL_VAL (1e-37F) +#define SMALL_NORMAL_EXP (-37) #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #define DEC_VAL_MAX 1e200 +#define SMALL_NORMAL_VAL (1e-307) +#define SMALL_NORMAL_EXP (-307) #endif const char *top = str + len; @@ -275,8 +280,13 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool exp_val = -exp_val; } - // apply the exponent - dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val + exp_extra); + // apply the exponent, making sure it's not a subnormal value + exp_val += exp_extra; + if (exp_val < SMALL_NORMAL_EXP) { + exp_val -= SMALL_NORMAL_EXP; + dec_val *= SMALL_NORMAL_VAL; + } + dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val); } // negate value if needed diff --git a/py/persistentcode.c b/py/persistentcode.c index e0bb8f1d6..7113b0dc2 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -200,7 +200,11 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) { // create raw_code and return it mp_raw_code_t *rc = mp_emit_glue_new_raw_code(); - mp_emit_glue_assign_bytecode(rc, bytecode, bc_len, const_table, + mp_emit_glue_assign_bytecode(rc, bytecode, + #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS + bc_len, + #endif + const_table, #if MICROPY_PERSISTENT_CODE_SAVE n_obj, n_raw_code, #endif diff --git a/py/py.mk b/py/py.mk index de82a971b..7c4cf82d8 100644 --- a/py/py.mk +++ b/py/py.mk @@ -101,7 +101,7 @@ $(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS) endif # py object files -PY_O_BASENAME = \ +PY_CORE_O_BASENAME = $(addprefix py/,\ mpstate.o \ nlr.o \ nlrx86.o \ @@ -158,6 +158,7 @@ PY_O_BASENAME = \ objcell.o \ objclosure.o \ objcomplex.o \ + objdeque.o \ objdict.o \ objenumerate.o \ objexcept.o \ @@ -213,41 +214,47 @@ 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_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),) @@ -260,8 +267,8 @@ PY_O += $(BUILD)/$(BUILD)/frozen_mpy.o endif # Sources that may contain qstrings -SRC_QSTR_IGNORE = nlr% emitnx86% emitnx64% emitnthumb% emitnarm% emitnxtensa% -SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_O_BASENAME:.o=.c)) emitnative.c) +SRC_QSTR_IGNORE = py/nlr% py/emitnx86% py/emitnx64% py/emitnthumb% py/emitnarm% py/emitnxtensa% +SRC_QSTR = $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) py/emitnative.c $(PY_EXTMOD_O_BASENAME:.o=.c) # Anything that depends on FORCE will be considered out-of-date FORCE: diff --git a/py/pystack.c b/py/pystack.c index 767c307e9..552e59d53 100644 --- a/py/pystack.c +++ b/py/pystack.c @@ -43,7 +43,8 @@ void *mp_pystack_alloc(size_t n_bytes) { #endif if (MP_STATE_THREAD(pystack_cur) + n_bytes > MP_STATE_THREAD(pystack_end)) { // out of memory in the pystack - mp_raise_recursion_depth(); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, + MP_OBJ_NEW_QSTR(MP_QSTR_pystack_space_exhausted))); } void *ptr = MP_STATE_THREAD(pystack_cur); MP_STATE_THREAD(pystack_cur) += n_bytes; diff --git a/py/qstr.h b/py/qstr.h index 63fd0c369..f4375ee0e 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); diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 1b480c9c7..a60905812 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -52,3 +52,7 @@ Q() Q() Q() Q(utf-8) + +#if MICROPY_ENABLE_PYSTACK +Q(pystack exhausted) +#endif diff --git a/py/repl.c b/py/repl.c index 7e8922e19..61ae2c1fe 100644 --- a/py/repl.c +++ b/py/repl.c @@ -27,6 +27,7 @@ #include #include "py/obj.h" #include "py/runtime.h" +#include "py/builtin.h" #include "py/repl.h" #if MICROPY_HELPER_REPL @@ -136,8 +137,11 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print } } - // begin search in locals dict - mp_obj_dict_t *dict = mp_locals_get(); + size_t nqstr = QSTR_TOTAL(); + + // begin search in outer global dict which is accessed from __main__ + mp_obj_t obj = MP_OBJ_FROM_PTR(&mp_module___main__); + mp_obj_t dest[2]; for (;;) { // get next word in string to complete @@ -148,43 +152,20 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print size_t s_len = str - s_start; if (str < top) { - // a complete word, lookup in current dict - - mp_obj_t obj = MP_OBJ_NULL; - for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - size_t d_len; - const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); - if (s_len == d_len && strncmp(s_start, d_str, d_len) == 0) { - obj = dict->map.table[i].value; - break; - } - } + // a complete word, lookup in current object + qstr q = qstr_find_strn(s_start, s_len); + if (q == MP_QSTR_NULL) { + // lookup will fail + return 0; } + mp_load_method_maybe(obj, q, dest); + obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found if (obj == MP_OBJ_NULL) { // lookup failed return 0; } - // found an object of this name; try to get its dict - if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) { - dict = mp_obj_module_get_globals(obj); - } else { - mp_obj_type_t *type; - if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) { - type = MP_OBJ_TO_PTR(obj); - } else { - type = mp_obj_get_type(obj); - } - if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) { - dict = type->locals_dict; - } else { - // obj has no dict - return 0; - } - } - // skip '.' to move to next word ++str; @@ -192,14 +173,15 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print // end of string, do completion on this partial name // look for matches - int n_found = 0; const char *match_str = NULL; size_t match_len = 0; - for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - size_t d_len; - const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); - if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + qstr q_first = 0, q_last; + for (qstr q = 1; q < nqstr; ++q) { + size_t d_len; + const char *d_str = (const char*)qstr_data(q, &d_len); + if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + mp_load_method_maybe(obj, q, dest); + if (dest[0] != MP_OBJ_NULL) { if (match_str == NULL) { match_str = d_str; match_len = d_len; @@ -213,13 +195,16 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print } } } - ++n_found; + if (q_first == 0) { + q_first = q; + } + q_last = q; } } } // nothing found - if (n_found == 0) { + if (q_first == 0) { // If there're no better alternatives, and if it's first word // in the line, try to complete "import". if (s_start == org_str) { @@ -234,7 +219,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print } // 1 match found, or multiple matches with a common prefix - if (n_found == 1 || match_len > s_len) { + if (q_first == q_last || match_len > s_len) { *compl_str = match_str + s_len; return match_len - s_len; } @@ -245,11 +230,12 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print #define MAX_LINE_LEN (4 * WORD_SLOT_LEN) int line_len = MAX_LINE_LEN; // force a newline for first word - for (size_t i = 0; i < dict->map.alloc; i++) { - if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - size_t d_len; - const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); - if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + for (qstr q = q_first; q <= q_last; ++q) { + size_t d_len; + const char *d_str = (const char*)qstr_data(q, &d_len); + if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { + mp_load_method_maybe(obj, q, dest); + if (dest[0] != MP_OBJ_NULL) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; if (gap < 2) { gap += WORD_SLOT_LEN; diff --git a/py/runtime.c b/py/runtime.c index 9dff9847a..54ec0d70b 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1215,13 +1215,12 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th if (type->iternext != NULL && send_value == mp_const_none) { mp_obj_t ret = type->iternext(self_in); + *ret_val = ret; if (ret != MP_OBJ_STOP_ITERATION) { - *ret_val = ret; return MP_VM_RETURN_YIELD; } else { // Emulate raise StopIteration() // Special case, handled in vm.c - *ret_val = MP_OBJ_NULL; return MP_VM_RETURN_NORMAL; } } @@ -1337,6 +1336,8 @@ import_error: return dest[0]; } + #if MICROPY_ENABLE_EXTERNAL_IMPORT + // See if it's a package, then can try FS import if (!mp_obj_is_package(module)) { goto import_error; @@ -1363,6 +1364,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) { diff --git a/py/unicode.c b/py/unicode.c index 140b7ba71..935dc9012 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 b18a2b5e3..2a8e3c990 100644 --- a/py/vm.c +++ b/py/vm.c @@ -48,14 +48,6 @@ // top element. // Exception stack also grows up, top element is also pointed at. -// Exception stack unwind reasons (WHY_* in CPython-speak) -// TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds -// left to do encoded in the JUMP number -typedef enum { - UNWIND_RETURN = 1, - UNWIND_JUMP, -} mp_unwind_reason_t; - #define DECODE_UINT \ mp_uint_t unum = 0; \ do { \ @@ -613,29 +605,18 @@ dispatch_loop: mp_call_method_n_kw(3, 0, sp); SET_TOP(mp_const_none); } else if (MP_OBJ_IS_SMALL_INT(TOP())) { - mp_int_t cause_val = MP_OBJ_SMALL_INT_VALUE(TOP()); - if (cause_val == UNWIND_RETURN) { - // stack: (..., __exit__, ctx_mgr, ret_val, UNWIND_RETURN) - mp_obj_t ret_val = sp[-1]; - sp[-1] = mp_const_none; - sp[0] = mp_const_none; - sp[1] = mp_const_none; - mp_call_method_n_kw(3, 0, sp - 3); - sp[-3] = ret_val; - sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN); - } else { - assert(cause_val == UNWIND_JUMP); - // stack: (..., __exit__, ctx_mgr, dest_ip, num_exc, UNWIND_JUMP) - mp_obj_t dest_ip = sp[-2]; - mp_obj_t num_exc = sp[-1]; - sp[-2] = mp_const_none; - sp[-1] = mp_const_none; - sp[0] = mp_const_none; - mp_call_method_n_kw(3, 0, sp - 4); - sp[-4] = dest_ip; - sp[-3] = num_exc; - sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP); - } + // Getting here there are two distinct cases: + // - unwind return, stack: (..., __exit__, ctx_mgr, ret_val, SMALL_INT(-1)) + // - unwind jump, stack: (..., __exit__, ctx_mgr, dest_ip, SMALL_INT(num_exc)) + // For both cases we do exactly the same thing. + mp_obj_t data = sp[-1]; + mp_obj_t cause = sp[0]; + sp[-1] = mp_const_none; + sp[0] = mp_const_none; + sp[1] = mp_const_none; + mp_call_method_n_kw(3, 0, sp - 3); + sp[-3] = data; + sp[-2] = cause; sp -= 2; // we removed (__exit__, ctx_mgr) } else { assert(mp_obj_is_exception_instance(TOP())); @@ -680,10 +661,11 @@ unwind_jump:; // of a "with" block contains the context manager info. // We're going to run "finally" code as a coroutine // (not calling it recursively). Set up a sentinel - // on a stack so it can return back to us when it is + // on the stack so it can return back to us when it is // done (when WITH_CLEANUP or END_FINALLY reached). - PUSH((mp_obj_t)unum); // push number of exception handlers left to unwind - PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP)); // push sentinel + // The sentinel is the number of exception handlers left to + // unwind, which is a non-negative integer. + PUSH(MP_OBJ_NEW_SMALL_INT(unum)); ip = exc_sp->handler; // get exception handler byte code address exc_sp--; // pop exception handler goto dispatch_loop; // run the exception handler @@ -720,11 +702,14 @@ unwind_jump:; } else if (MP_OBJ_IS_SMALL_INT(TOP())) { // We finished "finally" coroutine and now dispatch back // to our caller, based on TOS value - mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP()); - if (reason == UNWIND_RETURN) { + mp_int_t cause = MP_OBJ_SMALL_INT_VALUE(POP()); + if (cause < 0) { + // A negative cause indicates unwind return goto unwind_return; } else { - assert(reason == UNWIND_JUMP); + // Otherwise it's an unwind jump and we must push as a raw + // number the number of exception handlers to unwind + PUSH((mp_obj_t)cause); goto unwind_jump; } } else { @@ -1101,7 +1086,7 @@ unwind_return: // (not calling it recursively). Set up a sentinel // on a stack so it can return back to us when it is // done (when WITH_CLEANUP or END_FINALLY reached). - PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN)); + PUSH(MP_OBJ_NEW_SMALL_INT(-1)); ip = exc_sp->handler; exc_sp--; goto dispatch_loop; @@ -1177,6 +1162,7 @@ yield: mp_obj_t send_value = POP(); mp_obj_t t_exc = MP_OBJ_NULL; mp_obj_t ret_value; + code_state->sp = sp; // Save sp because it's needed if mp_resume raises StopIteration if (inject_exc != MP_OBJ_NULL) { t_exc = inject_exc; inject_exc = MP_OBJ_NULL; @@ -1192,8 +1178,7 @@ yield: } else if (ret_kind == MP_VM_RETURN_NORMAL) { // Pop exhausted gen sp--; - // TODO: When ret_value can be MP_OBJ_NULL here?? - if (ret_value == MP_OBJ_NULL || ret_value == MP_OBJ_STOP_ITERATION) { + if (ret_value == MP_OBJ_STOP_ITERATION) { // Optimize StopIteration // TODO: get StopIteration's value PUSH(mp_const_none); @@ -1376,7 +1361,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 } @@ -1389,8 +1375,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 diff --git a/tests/basics/builtin_dir.py b/tests/basics/builtin_dir.py index 16e7e669e..c15a76f4c 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 64% rename from tests/basics/enumerate.py rename to tests/basics/builtin_enumerate.py index 4f8239bf7..fcbf86976 100644 --- a/tests/basics/enumerate.py +++ b/tests/basics/builtin_enumerate.py @@ -14,3 +14,10 @@ print(list(enumerate(range(100)))) print(list(enumerate([1, 2, 3], start=1))) print(list(enumerate(iterable=[1, 2, 3]))) print(list(enumerate(iterable=[1, 2, 3], start=1))) + +# check handling of extra positional args (exercises some logic in mp_arg_parse_all) +# don't print anything because it doesn't error with MICROPY_CPYTHON_COMPAT disabled +try: + enumerate([], 1, 2) +except TypeError: + pass diff --git a/tests/basics/builtin_eval.py b/tests/basics/builtin_eval.py index 8b9d02e61..9b49a2015 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 671eedab6..ef0a32da0 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 fd4e65c53..2e417a43a 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 100% rename from tests/basics/hasattr1.py rename to tests/basics/builtin_hasattr.py diff --git a/tests/basics/map.py b/tests/basics/builtin_map.py similarity index 100% rename from tests/basics/map.py rename to tests/basics/builtin_map.py diff --git a/tests/basics/print.py b/tests/basics/builtin_print.py similarity index 100% rename from tests/basics/print.py rename to tests/basics/builtin_print.py diff --git a/tests/basics/builtin_range_binop.py b/tests/basics/builtin_range_binop.py new file mode 100644 index 000000000..e4e054c27 --- /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/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 9693aca81..e4acb14ca 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/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 1d97e6b16..0b6b14fa5 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/del_attr.py b/tests/basics/del_attr.py index bec7afb84..8487b97e3 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 000000000..19966fcb0 --- /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 000000000..22d370e94 --- /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 000000000..3df8acf40 --- /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 000000000..4261a0655 --- /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 000000000..ffaeb4085 --- /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/fun_calldblstar2.py b/tests/basics/fun_calldblstar2.py index cf982ef5b..8795eaf15 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 367fe0b7f..3e79c727b 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 2a00396e6..39fd0af14 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/gc1.py b/tests/basics/gc1.py index dcbe0bfcf..332bf9744 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 5196b48d2..4e68aec63 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/lexer.py b/tests/basics/lexer.py index 244de8cb9..181d62db1 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/op_error.py b/tests/basics/op_error.py index b30b5f0a3..7b4f896e1 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 432c05a9f..7def75b0c 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 8d4403f77..233f7f9ab 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 d5cc59ad6..36531f11c 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/subclass_native_call.py b/tests/basics/subclass_native_call.py new file mode 100644 index 000000000..c64557522 --- /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 000000000..d81cc0710 --- /dev/null +++ b/tests/basics/subclass_native_call.py.exp @@ -0,0 +1 @@ +42 diff --git a/tests/basics/syntaxerror.py b/tests/basics/syntaxerror.py index 843459f0b..8e706c6e2 100644 --- a/tests/basics/syntaxerror.py +++ b/tests/basics/syntaxerror.py @@ -1,5 +1,11 @@ # test syntax errors +try: + exec +except NameError: + print("SKIP") + raise SystemExit + def test_syntax(code): try: exec(code) diff --git a/tests/basics/sys_getsizeof.py b/tests/basics/sys_getsizeof.py index d16eb1561..fe1b403e0 100644 --- a/tests/basics/sys_getsizeof.py +++ b/tests/basics/sys_getsizeof.py @@ -13,3 +13,10 @@ print(sys.getsizeof({1: 2}) >= 2) class A: pass print(sys.getsizeof(A()) > 0) + +# Only test deque if we have it +try: + from ucollections import deque + assert sys.getsizeof(deque((), 1)) > 0 +except ImportError: + pass diff --git a/tests/cmdline/repl_autocomplete.py b/tests/cmdline/repl_autocomplete.py index a848cab0f..27cad428f 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 dfb998ff6..75002985e 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/types_exception_subclassinit.py b/tests/cpydiff/types_exception_subclassinit.py index 56bab51d1..39cdaf45b 100644 --- a/tests/cpydiff/types_exception_subclassinit.py +++ b/tests/cpydiff/types_exception_subclassinit.py @@ -4,9 +4,9 @@ description: Exception.__init__ method does not exist. cause: Subclassing native classes is not fully supported in MicroPython. workaround: Call using ``super()`` instead:: -class A(Exception): - def __init__(self): - super().__init__() + class A(Exception): + def __init__(self): + super().__init__() """ class A(Exception): def __init__(self): diff --git a/tests/extmod/time_ms_us.py b/tests/extmod/time_ms_us.py index 31f07d31b..135cf1e09 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 dbde42265..b8ca7e7ef 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/ujson_dump.py b/tests/extmod/ujson_dump.py new file mode 100644 index 000000000..c80e533ed --- /dev/null +++ b/tests/extmod/ujson_dump.py @@ -0,0 +1,18 @@ +try: + from uio import StringIO + import ujson as json +except: + try: + from io import StringIO + import json + except ImportError: + print("SKIP") + raise SystemExit + +s = StringIO() +json.dump(False, s) +print(s.getvalue()) + +s = StringIO() +json.dump({"a": (2, [3, None])}, s) +print(s.getvalue()) diff --git a/tests/extmod/uzlib_decompress.py b/tests/extmod/uzlib_decompress.py index 63247955c..dd6e4876f 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_fat_fileio1.py b/tests/extmod/vfs_fat_fileio1.py index d19df120b..f1f4639ab 100644 --- a/tests/extmod/vfs_fat_fileio1.py +++ b/tests/extmod/vfs_fat_fileio1.py @@ -91,10 +91,8 @@ with open("foo_file.txt") as f2: f2.seek(0, 1) # SEEK_CUR print(f2.read(1)) - try: - f2.seek(1, 1) # SEEK_END - except OSError as e: - print(e.args[0] == uerrno.EOPNOTSUPP) + f2.seek(2, 1) # SEEK_CUR + print(f2.read(1)) f2.seek(-2, 2) # SEEK_END print(f2.read(1)) @@ -115,3 +113,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 d777585cf..4eb50402c 100644 --- a/tests/extmod/vfs_fat_fileio1.py.exp +++ b/tests/extmod/vfs_fat_fileio1.py.exp @@ -7,7 +7,12 @@ hello!world! 12 h e -True +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.exp b/tests/extmod/vfs_fat_fileio2.py.exp index 118dee26b..268405364 100644 --- a/tests/extmod/vfs_fat_fileio2.py.exp +++ b/tests/extmod/vfs_fat_fileio2.py.exp @@ -3,9 +3,9 @@ True True b'data in file' True -[('sub_file.txt', 32768, 0), ('file.txt', 32768, 0)] -[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)] -[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)] +[('sub_file.txt', 32768, 0, 11), ('file.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 8)] new text -[('moved-to-root.txt', 32768, 0)] +[('moved-to-root.txt', 32768, 0, 8)] ENOSPC: True diff --git a/tests/extmod/vfs_fat_oldproto.py.exp b/tests/extmod/vfs_fat_oldproto.py.exp index ab8338cbb..b97468316 100644 --- a/tests/extmod/vfs_fat_oldproto.py.exp +++ b/tests/extmod/vfs_fat_oldproto.py.exp @@ -1,3 +1,3 @@ -[('file.txt', 32768, 0)] +[('file.txt', 32768, 0, 6)] hello! [] diff --git a/tests/extmod/vfs_fat_ramdisk.py.exp b/tests/extmod/vfs_fat_ramdisk.py.exp index ccd0f7134..ef6cf1e72 100644 --- a/tests/extmod/vfs_fat_ramdisk.py.exp +++ b/tests/extmod/vfs_fat_ramdisk.py.exp @@ -3,7 +3,7 @@ True statvfs: (512, 512, 16, 16, 16, 0, 0, 0, 0, 255) getcwd: / True -[('foo_file.txt', 32768, 0)] +[('foo_file.txt', 32768, 0, 6)] stat root: (16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) stat file: (32768, 0, 0, 0, 0, 0, 6) True @@ -12,5 +12,5 @@ getcwd: /foo_dir [] True getcwd: / -[(b'foo_file.txt', 32768, 0), (b'foo_dir', 16384, 0)] +[(b'foo_file.txt', 32768, 0, 6), (b'foo_dir', 16384, 0, 0)] ENOENT: True diff --git a/tests/float/builtin_float_pow.py b/tests/float/builtin_float_pow.py new file mode 100644 index 000000000..2de1b4817 --- /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/float_format.py b/tests/float/float_format.py new file mode 100644 index 000000000..d43535cf2 --- /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 index 448eff3bc..5eb16e79c 100644 --- a/tests/float/float_parse.py +++ b/tests/float/float_parse.py @@ -7,9 +7,8 @@ print(float('1234') - float('0.1234e4')) print(float('1.015625') - float('1015625e-6')) # very large integer part with a very negative exponent should cancel out -print(float('9' * 60 + 'e-60')) -print(float('9' * 60 + 'e-40')) -print(float('9' * 60 + 'e-20') == float('1e40')) +print('%.4e' % float('9' * 60 + 'e-60')) +print('%.4e' % float('9' * 60 + 'e-40')) # many fractional digits print(float('.' + '9' * 70)) @@ -20,3 +19,8 @@ print(float('.' + '9' * 70 + 'e-50') == float('1e-50')) print(float('.' + '0' * 60 + '1e10') == float('1e-51')) print(float('.' + '0' * 60 + '9e25')) print(float('.' + '0' * 60 + '9e40')) + +# ensure that accuracy is retained when value is close to a subnormal +print(float('1.00000000000000000000e-37')) +print(float('10.0000000000000000000e-38')) +print(float('100.000000000000000000e-39')) diff --git a/tests/float/float_parse_doubleprec.py b/tests/float/float_parse_doubleprec.py index 356601130..dcc0dd592 100644 --- a/tests/float/float_parse_doubleprec.py +++ b/tests/float/float_parse_doubleprec.py @@ -11,6 +11,11 @@ print(float('.' + '9' * 400 + 'e100')) print(float('.' + '9' * 400 + 'e-100')) # tiny fraction with large exponent -print(float('.' + '0' * 400 + '9e100')) -print(float('.' + '0' * 400 + '9e200')) -print(float('.' + '0' * 400 + '9e400')) +print('%.14e' % float('.' + '0' * 400 + '9e100')) +print('%.14e' % float('.' + '0' * 400 + '9e200')) +print('%.14e' % float('.' + '0' * 400 + '9e400')) + +# ensure that accuracy is retained when value is close to a subnormal +print(float('1.00000000000000000000e-307')) +print(float('10.0000000000000000000e-308')) +print(float('100.000000000000000000e-309')) diff --git a/tests/micropython/heap_lock.py b/tests/micropython/heap_lock.py index 0f0a70eff..ca3f5806a 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 67b208cfc..819c32663 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_iter.py b/tests/micropython/heapalloc_iter.py index 30ac82e14..163e17211 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 diff --git a/tests/pyb/can.py b/tests/pyb/can.py index 0fd8c8368..8a08ea9a6 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 e25a0f406..687935e7f 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/run-tests b/tests/run-tests index 8719befbd..627fa40da 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -54,6 +54,7 @@ def run_micropython(pyb, args, test_file, is_special=False): 'micropython/meminfo.py', 'basics/bytes_compare3.py', 'basics/builtin_help.py', 'thread/thread_exc2.py', ) + had_crash = False if pyb is None: # run on PC if test_file.startswith(('cmdline/', 'feature_check/')) or test_file in special_tests: @@ -128,8 +129,9 @@ def run_micropython(pyb, args, test_file, is_special=False): # run the actual test try: output_mupy = subprocess.check_output(cmdlist, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError: - output_mupy = b'CRASH' + except subprocess.CalledProcessError as er: + had_crash = True + output_mupy = er.output + b'CRASH' # clean up if we had an intermediate .mpy file if args.via_mpy: @@ -142,13 +144,14 @@ def run_micropython(pyb, args, test_file, is_special=False): try: output_mupy = pyb.execfile(test_file) except pyboard.PyboardError: + had_crash = True output_mupy = b'CRASH' # canonical form for all ports/platforms is to use \n for end-of-line output_mupy = output_mupy.replace(b'\r\n', b'\n') # don't try to convert the output if we should skip this test - if output_mupy in (b'SKIP\n', b'CRASH'): + if had_crash or output_mupy in (b'SKIP\n', b'CRASH'): return output_mupy if is_special or test_file in special_tests: diff --git a/tests/stress/dict_create_max.py b/tests/stress/dict_create_max.py new file mode 100644 index 000000000..3c75db20d --- /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/unix/extra_coverage.py b/tests/unix/extra_coverage.py index 7a496aa87..65011198d 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -71,3 +71,8 @@ try: import frzmpy2 except ZeroDivisionError: print('ZeroDivisionError') + +# test loading a resource from a frozen string +import uio +buf = uio.resource_stream('frzstr_pkg2', 'mod.py') +print(buf.read(21)) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index bbac5f3d7..009874509 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -13,6 +13,9 @@ false true 80000000 80000000 abc +# GC +0 +0 # vstr tests sts @@ -24,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' @@ -48,8 +59,10 @@ Warning: test +1e+00 +1e+00 # binary -122 +123 456 +# VM +2 1 # scheduler sched(0)=1 sched(1)=1 @@ -91,3 +104,4 @@ frzstr_pkg2.mod frzmpy_pkg2.mod 1 ZeroDivisionError +b'# test frozen package'