diff options
177 files changed, 4348 insertions, 944 deletions
diff --git a/.travis.yml b/.travis.yml index 6a99fdaf9b..7ae9f4952d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,8 @@ before_script: - sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded - sudo dpkg --add-architecture i386 - sudo apt-get update -qq || true - - sudo apt-get install -y python3 gcc-multilib gcc-arm-none-eabi pkg-config libffi-dev libffi-dev:i386 qemu-system mingw32 + - sudo apt-get install -y python3 gcc-multilib pkg-config libffi-dev libffi-dev:i386 qemu-system mingw32 + - sudo apt-get install -y --force-yes gcc-arm-none-eabi # For teensy build - sudo apt-get install realpath # For coverage testing diff --git a/CODECONVENTIONS.md b/CODECONVENTIONS.md index 951adee91f..fa90940cc4 100644 --- a/CODECONVENTIONS.md +++ b/CODECONVENTIONS.md @@ -1,3 +1,31 @@ +Git commit conventions +====================== + +Each commit message should start with a directory or full file path +prefix, so it was clear which part of codebase a commit affects. If +a change affects one file, it's better to use path to a file. If it +affects few files in a subdirectory, using subdirectory as a prefix +is ok. For longish paths, it's acceptable to drop intermediate +components, which still should provide good context of a change. +It's also ok to drop file extensions. + +Besides prefix, first line of a commit message should describe a +change clearly and to the point, and be a grammatical sentence with +final full stop. First line should fit within 78 characters. Examples +of good first line of commit messages: + + py/objstr: Add splitlines() method. + py: Rename FOO to BAR. + docs/machine: Fix typo in reset() description. + ports: Switch to use lib/foo instead of duplicated code. + +After the first line, add an empty line and in following lines describe +a change in a detail, if needed. Any change beyond 5 lines would likely +require such detailed description. + +To get good practical examples of good commits and their messages, browse +thry the `git log` of the project. + Python code conventions ======================= @@ -54,6 +54,8 @@ Additional components: - tools/ -- various tools, including the pyboard.py module. - examples/ -- a few example Python scripts. +The subdirectories above may include READMEs with additional info. + "make" is used to build the components, or "gmake" on BSD-based systems. You will also need bash and Python (at least 2.7 or 3.3). @@ -69,6 +71,7 @@ Alternatively, fallback implementation based on setjmp/longjmp can be used. To build (see section below for required dependencies): $ cd unix + $ make axtls $ make Then to give it a try: diff --git a/docs/README.md b/docs/README.md index c594030999..2602a15225 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,3 +26,15 @@ In `micropython/docs`, build the docs: Where `<port_name>` can be `unix`, `pyboard`, `wipy` or `esp8266`. You'll find the index page at `micropython/docs/build/<port_name>/html/index.html`. + +PDF manual generation +--------------------- + +This can be achieved with: + + make MICROPY_PORT=<port_name> latexpdf + +but require rather complete install of LaTeX with various extensions. On +Debiab/Ubuntu, try (500MB+ download): + + apt-get install texlive-latex-recommended texlive-latex-extra diff --git a/docs/conf.py b/docs/conf.py index 9163e04c79..6faeb60406 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -93,7 +93,7 @@ copyright = '2014-2016, Damien P. George and contributors' # The short X.Y version. version = '1.8' # The full version, including alpha/beta/rc tags. -release = '1.8' +release = '1.8.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/esp8266/general.rst b/docs/esp8266/general.rst index f996068d09..313e6074c1 100644 --- a/docs/esp8266/general.rst +++ b/docs/esp8266/general.rst @@ -6,8 +6,8 @@ ESP8266 is a popular WiFi-enabled System-on-Chip (SoC) by Espressif Systems. Multitude of boards ------------------- -There are multitude of modules and boards from different sources which carry -ESP8266 chip. MicroPython tries to provide a generic port which would run on +There are a multitude of modules and boards from different sources which carry +the ESP8266 chip. MicroPython tries to provide a generic port which would run on as many boards/modules as possible, but there may be limitations. Adafruit Feather HUZZAH board is taken as a reference board for the port (for example, testing is performed on it). If you have another board, please make sure you @@ -18,13 +18,13 @@ To make a generic ESP8266 port and support as many boards as possible, following design and implementation decision were made: * GPIO pin numbering is based on ESP8266 chip numbering, not some "logical" - numbering of a particular board. Please have manual/pin diagram of your board - handy to find correspondce between your board pins and actual ESP8266 pins. + numbering of a particular board. Please have the manual/pin diagram of your board + at hand to find correspondence between your board pins and actual ESP8266 pins. We also encourage users of various boards to share this mapping via MicroPython forum, with the idea to collect community-maintained reference materials eventually. * All pins which make sense to support, are supported by MicroPython - (for example, we don't expose pins which are used to connect SPI flash + (for example, pins which are used to connect SPI flash are not exposed, as they're unlikely useful for anything else, and operating on them will lead to board lock-up). However, any particular board may expose only subset of pins. Consult your board reference manual. @@ -37,10 +37,10 @@ Technical specifications and SoC datasheets The datasheets and other reference material for ESP8266 chip are available from the vendor site: http://bbs.espressif.com/viewtopic.php?f=67&t=225 . -The are primary reference for the chip technical specifications, capabilities, +They are the primary reference for the chip technical specifications, capabilities, operating modes, internal functioning, etc. -For your convinience, some of technical specifications are provided below: +For your convenience, some of technical specifications are provided below: * Architecture: Xtensa lx106 * CPU frequency: 80MHz overclockable to 160MHz @@ -64,18 +64,18 @@ Boot process On boot, MicroPython EPS8266 port executes ``_boot.py`` script from internal frozen modules. It mounts filesystem in FlashROM, or if it's not available, performs first-time setup of the module and creates the filesystem. This -part of boot process is considered fixed, and not available for customization +part of the boot process is considered fixed, and not available for customization for end users (even if you build from source, please refrain from changes to it; customization of early boot process is available only to advanced users and developers, who can diagnose themselves any issues arising from modifying the standard process). -Once filesystem is mounted, ``boot.py`` is executed from it. The standard +Once the filesystem is mounted, ``boot.py`` is executed from it. The standard version of this file is created during first-time module set up and by -defaults starts up a WebREPL daemon to handle incoming connections. This +default starts up a WebREPL daemon to handle incoming connections. This file is customizable by end users (for example, you may want to disable WebREPL for extra security, or add other services which should be run on -module start-up). But keep in mind that incorrect modifications to boot.py +a module start-up). But keep in mind that incorrect modifications to boot.py may still lead to boot loops or lock ups, requiring to reflash a module from scratch. @@ -89,5 +89,14 @@ the following in ``main.py``:: import my_app my_app.main() -This will allow to keep structure of your application clear, as well as +This will allow to keep the structure of your application clear, as well as allow to install multiple applications on a board, and switch among them. + + +Real-time clock +--------------- + +Due to limitations of the ESP8266 chip the internal real-time clock (RTC) +will overflow every 7:45h. If a long-term working RTC time is required then +``time()`` or ``localtime()`` must be called at least once within 7 hours. +MicroPython will then handle the overflow. diff --git a/docs/esp8266/img/adafruit_products_pinoutstop.jpg b/docs/esp8266/img/adafruit_products_pinoutstop.jpg Binary files differnew file mode 100644 index 0000000000..655e27aee3 --- /dev/null +++ b/docs/esp8266/img/adafruit_products_pinoutstop.jpg diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index bfded9bea1..779248369f 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -3,7 +3,7 @@ Quick reference for the ESP8266 =============================== -.. image:: https://learn.adafruit.com/system/assets/assets/000/028/689/medium640/adafruit_products_pinoutstop.jpg +.. image:: img/adafruit_products_pinoutstop.jpg :alt: Adafruit Feather HUZZAH board :width: 640px @@ -43,7 +43,7 @@ The ``network`` module:: wlan.scan() # scan for access points wlan.isconnected() # check if the station is connected to an AP wlan.connect('essid', 'password') # connect to an AP - wlan.mac() # get the interface's MAC adddress + wlan.config('mac') # get the interface's MAC adddress wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses ap = network.WLAN(network.AP_IF) # create access-point interface @@ -199,9 +199,6 @@ The I2C driver is implemented in software and works on all pins:: buf = bytearray(10) # create a buffer with 10 bytes i2c.writeto(0x3a, buf) # write the given buffer to the slave - i2c.readfrom(0x3a, 4, stop=False) # don't send a stop bit after reading - i2c.writeto(0x3a, buf, stop=False) # don't send a stop bit after writing - Deep-sleep mode --------------- @@ -274,31 +271,55 @@ For low-level driving of a NeoPixel:: import esp esp.neopixel_write(pin, grb_buf, is800khz) +APA102 driver +------------- + +Use the ``apa102`` module:: + + from machine import Pin + from apa102 import APA102 + + clock = Pin(14, Pin.OUT) # set GPIO14 to output to drive the clock + data = Pin(13, Pin.OUT) # set GPIO13 to output to drive the data + apa = APA102(clock, data, 8) # create APA102 driver on the clock and the data pin for 8 pixels + apa[0] = (255, 255, 255, 31) # set the first pixel to white with a maximum brightness of 31 + apa.write() # write data to all pixels + r, g, b, brightness = apa[0] # get first pixel colour + +For low-level driving of an APA102:: + + import esp + esp.apa102_write(clock_pin, data_pin, rgbi_buf) + WebREPL (web browser interactive prompt) ---------------------------------------- WebREPL (REPL over WebSockets, accessible via a web browser) is an experimental feature available in ESP8266 port. Download web client -from https://github.com/micropython/webrepl , and start daemon using:: +from https://github.com/micropython/webrepl (hosted version available +at http://micropython.org/webrepl), and start the daemon on a device +using:: import webrepl webrepl.start() -(Release version will have it started on boot by default.) +(Release versions have it started on boot by default.) On a first connection, you will be prompted to set password for future sessions to use. The supported way to use WebREPL is by connecting to ESP8266 access point, but the daemon is also started on STA interface if it is active, so if your -routers is set up and works correctly, you may also use it while connecting -to your normal Internet access point (use ESP8266 AP connection method if -face any issues). +router is set up and works correctly, you may also use WebREPL while connected +to your normal Internet access point (use the ESP8266 AP connection method +if you face any issues). WebREPL is an experimental feature and a work in progress, and has known -issues. There's also provision to transfer (both upload and download) -files over WebREPL connection, but it has unstable status (be ready to -reboot a module in case of issues). It still may be a practical way to +issues. + +There's also provision to transfer (both upload and download) +files over WebREPL connection, but it has even more experimental status +than the WebREPL terminal mode. It is still a practical way to get script files onto ESP8266, so give it a try using ``webrepl_cli.py`` -from the repository above. See forum for other community-supported -alternatives to transfer files to ESP8266. +from the repository above. See the MicroPython forum for other +community-supported alternatives to transfer files to ESP8266. diff --git a/docs/esp8266/tutorial/network_basics.rst b/docs/esp8266/tutorial/network_basics.rst index 02a7054858..42aed56642 100644 --- a/docs/esp8266/tutorial/network_basics.rst +++ b/docs/esp8266/tutorial/network_basics.rst @@ -62,7 +62,7 @@ connect to your WiFi network:: print('connecting to network...') sta_if.active(True) sta_if.connect('<essid>', '<password>') - while not network.isconnected(): + while not sta_if.isconnected(): pass print('network config:', sta_if.ifconfig()) diff --git a/docs/esp8266/tutorial/network_tcp.rst b/docs/esp8266/tutorial/network_tcp.rst index 0a1cca4457..80a494721d 100644 --- a/docs/esp8266/tutorial/network_tcp.rst +++ b/docs/esp8266/tutorial/network_tcp.rst @@ -36,7 +36,7 @@ information they hold. Using the IP address we can make a socket and connect to the server:: >>> s = socket.socket() - >>> s.connect(addr[0][-1]) + >>> s.connect(addr) Now that we are connected we can download and display the data:: diff --git a/docs/library/cmath.rst b/docs/library/cmath.rst index e45efee303..465cf54ad3 100644 --- a/docs/library/cmath.rst +++ b/docs/library/cmath.rst @@ -4,9 +4,12 @@ .. module:: cmath :synopsis: mathematical functions for complex numbers -The ``cmath`` module provides some basic mathematical funtions for +The ``cmath`` module provides some basic mathematical functions for working with complex numbers. +Availability: not available on WiPy and ESP8266. Floating point support +required for this module. + Functions --------- diff --git a/docs/library/index.rst b/docs/library/index.rst index 03e6502d95..e3d6e31575 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -1,9 +1,33 @@ MicroPython libraries ===================== -The following standard Python libraries are built in to MicroPython. - -For additional libraries, please download them from the `micropython-lib repository +This chapter describes modules (function and class libraries) which are built +into MicroPython. There are a few categories of 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. + +Note about the availability of 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 +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 +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. + +Beyond the built-in libraries described in this documentation, many more +modules from the Python standard library, as well as further MicroPython +extensions to it, can be found in the `micropython-lib repository <https://github.com/micropython/micropython-lib>`_. Python standard libraries and micro-libraries @@ -101,6 +125,7 @@ library. uos.rst ure.rst usocket.rst + ussl.rst ustruct.rst utime.rst uzlib.rst diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index 98e24f37dd..7399b9b6e9 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -86,13 +86,15 @@ Methods When no pins are given, then the default set of TX and RX pins is taken, and hardware flow control will be disabled. If pins=None, no pin assignment will be made. -.. method:: uart.deinit() +.. only:: not port_esp8266 - Turn off the UART bus. + .. method:: uart.deinit() -.. method:: uart.any() + Turn off the UART bus. - Return the number of characters available for reading. + .. method:: uart.any() + + Return the number of characters available for reading. .. method:: uart.read([nbytes]) @@ -127,11 +129,13 @@ Methods Return value: number of bytes written or ``None`` on timeout. -.. method:: uart.sendbreak() +.. only:: not port_esp8266 + + .. method:: uart.sendbreak() - Send a break condition on the bus. This drives the bus low for a duration - of 13 bits. - Return value: ``None``. + Send a break condition on the bus. This drives the bus low for a duration + of 13 bits. + Return value: ``None``. .. only:: port_wipy @@ -158,14 +162,16 @@ Methods Returns an irq object. -Constants ---------- +.. only:: not port_esp8266 + + Constants + --------- -.. data:: UART.EVEN -.. data:: UART.ODD + .. data:: UART.EVEN + .. data:: UART.ODD - parity types (anlong with ``None``) + parity types (anlong with ``None``) -.. data:: UART.RX_ANY + .. data:: UART.RX_ANY - IRQ trigger sources + IRQ trigger sources diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 14d75cb466..b103ec393d 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -18,25 +18,23 @@ Reset related functions Get the reset cause. See :ref:`constants <machine_constants>` for the possible return values. -.. only:: port_wipy - - Interrupt related functions - --------------------------- +Interrupt related functions +--------------------------- - .. function:: disable_irq() +.. function:: disable_irq() - Disable interrupt requests. - Returns the previous IRQ state: ``False``/``True`` for disabled/enabled IRQs - respectively. This return value can be passed to enable_irq to restore - the IRQ to its original state. + Disable interrupt requests. + Returns the previous IRQ state: ``False``/``True`` for disabled/enabled IRQs + respectively. This return value can be passed to enable_irq to restore + the IRQ to its original state. - .. function:: enable_irq(state=True) +.. function:: enable_irq(state=True) - Enable interrupt requests. - If ``state`` is ``True`` (the default value) then IRQs are enabled. - If ``state`` is ``False`` then IRQs are disabled. The most common use of - this function is to pass it the value returned by ``disable_irq`` to - exit a critical section. + Enable interrupt requests. + If ``state`` is ``True`` (the default value) then IRQs are enabled. + If ``state`` is ``False`` then IRQs are disabled. The most common use of + this function is to pass it the value returned by ``disable_irq`` to + exit a critical section. Power related functions ----------------------- @@ -103,6 +101,19 @@ Miscellaneous functions varies by hardware (so use substring of a full value if you expect a short ID). In some MicroPython ports, ID corresponds to the network MAC address. +.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000) + + Time a pulse on the given `pin`, and return the duration of the pulse in + microseconds. The `pulse_level` argument should be 0 to time a low pulse + or 1 to time a high pulse. + + The function first waits while the pin input is different to the `pulse_level` + parameter, then times the duration that the pin is equal to `pulse_level`. + If the pin is already equal to `pulse_level` then timing starts straight away. + + The function will raise an OSError with ETIMEDOUT if either of the waits is + longer than the given timeout value (which is in microseconds). + .. _machine_constants: Constants diff --git a/docs/library/math.rst b/docs/library/math.rst index 6ed42333c7..9d5cf7b4ba 100644 --- a/docs/library/math.rst +++ b/docs/library/math.rst @@ -4,11 +4,14 @@ .. module:: math :synopsis: mathematical functions -The ``math`` module provides some basic mathematical funtions for +The ``math`` module provides some basic mathematical functions for working with floating-point numbers. *Note:* On the pyboard, floating-point numbers have 32-bit precision. +Availability: not available on WiPy. Floating point support required +for this module. + Functions --------- diff --git a/docs/library/pyb.DAC.rst b/docs/library/pyb.DAC.rst index 6041151b0f..7b5b1a6821 100644 --- a/docs/library/pyb.DAC.rst +++ b/docs/library/pyb.DAC.rst @@ -66,6 +66,10 @@ Methods Reinitialise the DAC. ``bits`` can be 8 or 12. +.. method:: dac.deinit() + + De-initialise the DAC making its pin available for other uses. + .. method:: dac.noise(freq) Generate a pseudo-random noise signal. A new random sample is written diff --git a/docs/library/ussl.rst b/docs/library/ussl.rst index b66e23b2c8..5371ed1290 100644 --- a/docs/library/ussl.rst +++ b/docs/library/ussl.rst @@ -8,56 +8,79 @@ This module provides access to Transport Layer Security (often known as “Secure Sockets Layer”) encryption and peer authentication facilities for network sockets, both client-side and server-side. -Functions ---------- +.. only:: not port_wipy -.. function:: ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ca_certs=None) + Functions + --------- - Takes an instance sock of socket.socket, and returns an instance of ssl.SSLSocket, a subtype of - ``socket.socket``, which wraps the underlying socket in an SSL context. sock must be a ``SOCK_STREAM`` - socket and protocol number ``socket.IPPROTO_SEC``; other socket types are unsupported. Example:: + .. function:: ssl.wrap_socket(sock, server_side=False) - import socket - import ssl - s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC) - ss = ssl.wrap_socket(s) - ss.connect(socket.getaddrinfo('www.google.com', 443)[0][-1]) + 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 + server-side SSL socket should be created from a normal socket returned from + `accept()` on a non-SSL listening server socket. - Certificates must be used in order to validate the other side of the connection, and also to - authenticate ourselves with the other end. Such certificates must be stored as files using the - FTP server, and they must be placed in specific paths with specific names. + .. warning:: - - The certificate to validate the other side goes in: **'/flash/cert/ca.pem'** - - The certificate to authenticate ourselves goes in: **'/flash/cert/cert.pem'** - - The key for our own certificate goes in: **'/flash/cert/private.key'** + Currently, this function does NOT validate server certificates, which makes + an SSL connection established prone to man-in-the-middle attacks. - .. note:: - When these files are stored, they are placed inside the internal **hidden** file system - (just like firmware updates), and therefore they are never visible. +.. only:: port_wipy - For instance to connect to the Blynk servers using certificates, take the file ``ca.pem`` located - in the `blynk examples folder <https://github.com/wipy/wipy/tree/master/examples/blynk>`_ - and put it in '/flash/cert/'. Then do:: + Functions + --------- - import socket - import ssl - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC) - ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem') - ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1]) + .. function:: ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ca_certs=None) - SSL sockets inherit all methods and from the standard sockets, see the :mod:`usocket` module. + Takes an instance sock of socket.socket, and returns an instance of ssl.SSLSocket, a subtype of + ``socket.socket``, which wraps the underlying socket in an SSL context. sock must be a ``SOCK_STREAM`` + socket and protocol number ``socket.IPPROTO_SEC``; other socket types are unsupported. Example:: -Exceptions ----------- + import socket + import ssl + s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC) + ss = ssl.wrap_socket(s) + ss.connect(socket.getaddrinfo('www.google.com', 443)[0][-1]) -.. data:: ssl.SSLError + Certificates must be used in order to validate the other side of the connection, and also to + authenticate ourselves with the other end. Such certificates must be stored as files using the + FTP server, and they must be placed in specific paths with specific names. -Constants ---------- + - The certificate to validate the other side goes in: **'/flash/cert/ca.pem'** + - The certificate to authenticate ourselves goes in: **'/flash/cert/cert.pem'** + - The key for our own certificate goes in: **'/flash/cert/private.key'** -.. data:: ssl.CERT_NONE -.. data:: ssl.CERT_OPTIONAL -.. data:: ssl.CERT_REQUIRED + .. note:: - supported values in ``cert_reqs`` + When these files are stored, they are placed inside the internal **hidden** file system + (just like firmware updates), and therefore they are never visible. + + For instance to connect to the Blynk servers using certificates, take the file ``ca.pem`` located + in the `blynk examples folder <https://github.com/wipy/wipy/tree/master/examples/blynk>`_ + and put it in '/flash/cert/'. Then do:: + + import socket + import ssl + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC) + ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem') + ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1]) + + SSL sockets inherit all methods and from the standard sockets, see the :mod:`usocket` module. + + Exceptions + ---------- + + .. data:: ssl.SSLError + + Constants + --------- + + .. data:: ssl.CERT_NONE + .. data:: ssl.CERT_OPTIONAL + .. data:: ssl.CERT_REQUIRED + + supported values in ``cert_reqs`` diff --git a/docs/library/ustruct.rst b/docs/library/ustruct.rst index ae5b1be003..74e42af07a 100644 --- a/docs/library/ustruct.rst +++ b/docs/library/ustruct.rst @@ -7,6 +7,12 @@ See `Python struct <https://docs.python.org/3/library/struct.html>`_ for more information. +Supported size/byte order prefixes: ``@``, ``<``, ``>``, ``!``. + +Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``, +``L``, ``q``, ``Q``, ``s``, ``P``, ``f``, ``d`` (the latter 2 depending +on the floating-point support). + Functions --------- diff --git a/docs/wipy/tutorial/repl.rst b/docs/wipy/tutorial/repl.rst index ef69d91445..e7b51f9c59 100644 --- a/docs/wipy/tutorial/repl.rst +++ b/docs/wipy/tutorial/repl.rst @@ -52,7 +52,12 @@ or:: $ screen /dev/tty.usbmodem* 115200 -When you are finished and want to exit screen, type CTRL-A CTRL-\\. +When you are finished and want to exit ``screen``, type CTRL-A CTRL-\\. If your keyboard does not have a \\-key (i.e. you need an obscure combination for \\ like ALT-SHIFT-7) you can remap the ``quit`` command: + +- create ``~/.screenrc`` +- add ``bind q quit`` + +This will allow you to quit ``screen`` by hitting CTRL-A Q. Linux ----- diff --git a/drivers/cc3000/inc/cc3000_common.h b/drivers/cc3000/inc/cc3000_common.h index d263da6591..aa16242310 100644 --- a/drivers/cc3000/inc/cc3000_common.h +++ b/drivers/cc3000/inc/cc3000_common.h @@ -169,9 +169,9 @@ typedef INT32 time_t; typedef UINT32 clock_t; typedef INT32 suseconds_t; -typedef struct timeval timeval; +typedef struct cc3000_timeval cc3000_timeval; -struct timeval +struct cc3000_timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ diff --git a/drivers/cc3000/inc/socket.h b/drivers/cc3000/inc/socket.h index 8c2a0aa16b..96c814bf77 100644 --- a/drivers/cc3000/inc/socket.h +++ b/drivers/cc3000/inc/socket.h @@ -416,7 +416,7 @@ extern INT32 CC3000_EXPORT(connect)(INT32 sd, const sockaddr *addr, INT32 addrle // //***************************************************************************** extern INT16 CC3000_EXPORT(select)(INT32 nfds, fd_set *readsds, fd_set *writesds, - fd_set *exceptsds, struct timeval *timeout); + fd_set *exceptsds, struct cc3000_timeval *timeout); //***************************************************************************** // diff --git a/drivers/cc3000/src/socket.c b/drivers/cc3000/src/socket.c index 6261caeb0a..ddd7e56e80 100644 --- a/drivers/cc3000/src/socket.c +++ b/drivers/cc3000/src/socket.c @@ -587,7 +587,7 @@ INT32 CC3000_EXPORT(connect)(INT32 sd, const sockaddr *addr, INT32 addrlen) //***************************************************************************** INT16 CC3000_EXPORT(select)(INT32 nfds, fd_set *readsds, fd_set *writesds, fd_set *exceptsds, -struct timeval *timeout) +struct cc3000_timeval *timeout) { UINT8 *ptr, *args; tBsdSelectRecvParams tParams; diff --git a/drivers/dht/dht.c b/drivers/dht/dht.c new file mode 100644 index 0000000000..95b0744510 --- /dev/null +++ b/drivers/dht/dht.c @@ -0,0 +1,89 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "extmod/machine_pulse.h" +#include "drivers/dht/dht.h" + +STATIC mp_obj_t dht_readinto(mp_obj_t pin_in, mp_obj_t buf_in) { + mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(pin_in); + mp_hal_pin_open_drain(pin); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + + if (bufinfo.len < 5) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small")); + } + + // issue start command + mp_hal_pin_od_high(pin); + mp_hal_delay_ms(250); + mp_hal_pin_od_low(pin); + mp_hal_delay_ms(18); + + mp_uint_t irq_state = mp_hal_quiet_timing_enter(); + + // release the line so the device can respond + mp_hal_pin_od_high(pin); + mp_hal_delay_us_fast(10); + + // wait for device to respond + mp_uint_t ticks = mp_hal_ticks_us(); + while (mp_hal_pin_read(pin) != 0) { + if ((mp_uint_t)(mp_hal_ticks_us() - ticks) > 100) { + goto timeout; + } + } + + // time pulse, should be 80us + ticks = machine_time_pulse_us(pin, 1, 150); + if (ticks == (mp_uint_t)-1) { + goto timeout; + } + + // time 40 pulses for data (either 26us or 70us) + uint8_t *buf = bufinfo.buf; + for (int i = 0; i < 40; ++i) { + ticks = machine_time_pulse_us(pin, 1, 100); + if (ticks == (mp_uint_t)-1) { + goto timeout; + } + buf[i / 8] = (buf[i / 8] << 1) | (ticks > 48); + } + + mp_hal_quiet_timing_exit(irq_state); + return mp_const_none; + +timeout: + mp_hal_quiet_timing_exit(irq_state); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); +} +MP_DEFINE_CONST_FUN_OBJ_2(dht_readinto_obj, dht_readinto); diff --git a/drivers/dht/dht.h b/drivers/dht/dht.h new file mode 100644 index 0000000000..8274228ac6 --- /dev/null +++ b/drivers/dht/dht.h @@ -0,0 +1,3 @@ +#include "py/obj.h" + +MP_DECLARE_CONST_FUN_OBJ(dht_readinto_obj); diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py index 852e015a5e..3bccf72dae 100644 --- a/drivers/display/ssd1306.py +++ b/drivers/display/ssd1306.py @@ -3,6 +3,7 @@ import time import framebuf + # register definitions SET_CONTRAST = const(0x81) SET_ENTIRE_ON = const(0xa4) @@ -22,6 +23,7 @@ SET_PRECHARGE = const(0xd9) SET_VCOM_DESEL = const(0xdb) SET_CHARGE_PUMP = const(0x8d) + class SSD1306: def __init__(self, height, external_vcc): self.width = 128 @@ -91,6 +93,7 @@ class SSD1306: def text(self, string, x, y, col=1): self.framebuf.text(string, x, y, col) + class SSD1306_I2C(SSD1306): def __init__(self, height, i2c, addr=0x3c, external_vcc=False): self.i2c = i2c @@ -114,27 +117,34 @@ class SSD1306_I2C(SSD1306): def poweron(self): pass -# TODO convert this class to use the new hardware API + class SSD1306_SPI(SSD1306): - def __init__(self, height, spi, dc, res, cs=None, external_vcc=False): - rate = 10 * 1024 * 1024 - spi.init(spi.MASTER, baudrate=rate, polarity=0, phase=0) - dc.init(dc.OUT, dc.PULL_NONE, value=0) - res.init(res.OUT, dc.PULL_NONE, value=0) - if cs is not None: - cs.init(cs.OUT, cs.PULL_NONE, value=0) + def __init__(self, height, spi, dc, res, cs, external_vcc=False): + self.rate = 10 * 1024 * 1024 + dc.init(dc.OUT, value=0) + res.init(res.OUT, value=0) + cs.init(cs.OUT, value=1) self.spi = spi self.dc = dc self.res = res + self.cs = cs super().__init__(height, external_vcc) def write_cmd(self, cmd): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs.high() self.dc.low() - self.spi.send(cmd) + self.cs.low() + self.spi.write(bytearray([cmd])) + self.cs.high() def write_data(self, buf): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs.high() self.dc.high() - self.spi.send(buf) + self.cs.low() + self.spi.write(buf) + self.cs.high() def poweron(self): self.res.high() @@ -142,4 +152,3 @@ class SSD1306_SPI(SSD1306): self.res.low() time.sleep_ms(10) self.res.high() - time.sleep_ms(10) diff --git a/esp8266/Makefile b/esp8266/Makefile index d8786301a8..65093d819b 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -26,7 +26,7 @@ INC += -I$(BUILD) INC += -I$(ESP_SDK)/include # UART for "os" messages. 0 is normal UART as used by MicroPython REPL, -# 1 is debug UART (tx only). +# 1 is debug UART (tx only), -1 to disable. UART_OS = 0 CFLAGS_XTENSA = -fsingle-precision-constant -Wdouble-promotion \ @@ -65,6 +65,7 @@ SRC_C = \ esppwm.c \ esponewire.c \ espneopixel.c \ + espapa102.c \ intr.c \ modpyb.c \ modpybpin.c \ @@ -123,6 +124,10 @@ LIB_SRC_C = $(addprefix lib/,\ fatfs/option/ccsbcs.c \ ) +DRIVERS_SRC_C = $(addprefix drivers/,\ + dht/dht.c \ + ) + SRC_S = \ gchelper.s \ @@ -133,10 +138,11 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) #OBJ += $(BUILD)/pins_$(BOARD).o # List of sources for qstr extraction -SRC_QSTR += $(SRC_C) $(STM_SRC_C) $(EXTMOD_SRC_C) +SRC_QSTR += $(SRC_C) $(STM_SRC_C) $(EXTMOD_SRC_C) $(DRIVERS_SRC_C) # Append any auto-generated sources that are needed by sources listed in SRC_QSTR SRC_QSTR_AUTO_DEPS += diff --git a/esp8266/README.md b/esp8266/README.md index e187d4da17..0509a3799b 100644 --- a/esp8266/README.md +++ b/esp8266/README.md @@ -69,6 +69,34 @@ $ make PORT=/dev/ttyUSB0 deploy The image produced is `firmware-combined.bin`, to be flashed at 0x00000. +First start +----------- + +__Serial prompt__ + +You can access the REPL (Python prompt) over UART (the same as used for +programming). +- Baudrate: 115200 + +__WiFi__ + +Initally, the device configures itself as a WiFi access point (AP). +- ESSID: MicroPython-xxxxxx (x’s are replaced with part of the MAC address). +- Password: micropythoN (note the upper-case N). +- IP address of the board: 192.168.4.1. +- DHCP-server is activated. + +__WebREPL__ + +Python prompt over WiFi, connecting through a browser. +- Hosted at http://micropython.org/webrepl. +- GitHub repository https://github.com/micropython/webrepl. + +Please follow the instructions there. + +More detailed instructions can be found at +http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html + Troubleshooting --------------- diff --git a/esp8266/esp_mphal.c b/esp8266/esp_mphal.c index 25f1a9322f..9f090a0973 100644 --- a/esp8266/esp_mphal.c +++ b/esp8266/esp_mphal.c @@ -166,21 +166,24 @@ static int call_dupterm_read(void) { read_m[2] = MP_OBJ_NEW_SMALL_INT(1); mp_obj_t res = mp_call_method_n_kw(1, 0, read_m); if (res == mp_const_none) { + nlr_pop(); return -2; } mp_buffer_info_t bufinfo; mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ); if (bufinfo.len == 0) { - MP_STATE_PORT(term_obj) = NULL; - mp_printf(&mp_plat_print, "dupterm: EOF received, deactivating\n"); + mp_uos_deactivate("dupterm: EOF received, deactivating\n", MP_OBJ_NULL); + nlr_pop(); return -1; } nlr_pop(); + if (*(byte*)bufinfo.buf == interrupt_char) { + mp_keyboard_interrupt(); + return -2; + } return *(byte*)bufinfo.buf; } else { - MP_STATE_PORT(term_obj) = NULL; - mp_printf(&mp_plat_print, "dupterm: Exception in read() method, deactivating: "); - mp_obj_print_exception(&mp_plat_print, nlr.ret_val); + mp_uos_deactivate("dupterm: Exception in read() method, deactivating: ", nlr.ret_val); } return -1; @@ -213,7 +216,7 @@ void mp_hal_signal_dupterm_input(void) { system_os_post(DUPTERM_TASK_ID, 0, 0); } -void mp_hal_pin_config_od(mp_hal_pin_obj_t pin_id) { +void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin_id) { const pyb_pin_obj_t *pin = &pyb_pin_obj[pin_id]; if (pin->phys_port == 16) { diff --git a/esp8266/esp_mphal.h b/esp8266/esp_mphal.h index 13b1c8fdf0..91fee21198 100644 --- a/esp8266/esp_mphal.h +++ b/esp8266/esp_mphal.h @@ -28,6 +28,10 @@ #define _INCLUDED_MPHAL_H_ #include "py/ringbuf.h" +#include "xtirq.h" + +void mp_keyboard_interrupt(void); +extern int interrupt_char; struct _mp_print_t; // Structure for UART-only output via mp_printf() @@ -59,14 +63,19 @@ void ets_event_poll(void); #include "osapi.h" #define mp_hal_delay_us_fast(us) os_delay_us(us) +#define mp_hal_quiet_timing_enter() disable_irq() +#define mp_hal_quiet_timing_exit(irq_state) enable_irq(irq_state) + // C-level pin HAL #include "etshal.h" #include "gpio.h" #include "esp8266/modpyb.h" #define mp_hal_pin_obj_t uint32_t #define mp_hal_get_pin_obj(o) mp_obj_get_pin(o) -void mp_hal_pin_config_od(mp_hal_pin_obj_t pin); -#define mp_hal_pin_low(p) do { \ +void mp_hal_pin_input(mp_hal_pin_obj_t pin); +void mp_hal_pin_output(mp_hal_pin_obj_t pin); +void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin); +#define mp_hal_pin_od_low(p) do { \ if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | 1); } \ else { gpio_output_set(0, 1 << (p), 1 << (p), 0); } \ } while (0) diff --git a/esp8266/espapa102.c b/esp8266/espapa102.c new file mode 100644 index 0000000000..e5f3024b10 --- /dev/null +++ b/esp8266/espapa102.c @@ -0,0 +1,110 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Robert Foss, Daniel Busch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include "c_types.h" +#include "eagle_soc.h" +#include "user_interface.h" +#include "espapa102.h" + +#define NOP asm volatile(" nop \n\t") + +static inline void _esp_apa102_send_byte(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t byte) { + for (uint32_t i = 0; i < 8; i++) { + if (byte & 0x80) { + // set data pin high + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask); + } else { + // set data pin low + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, dataPinMask); + } + + // set clock pin high + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask); + byte <<= 1; + NOP; + NOP; + + // set clock pin low + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask); + NOP; + NOP; + } +} + +static inline void _esp_apa102_send_colors(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t *pixels, uint32_t numBytes) { + for (uint32_t i = 0; i < numBytes / 4; i++) { + _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 3] | 0xE0); + _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 2]); + _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 1]); + _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4]); + } +} + +static inline void _esp_apa102_start_frame(uint32_t clockPinMask, uint32_t dataPinMask) { + for (uint32_t i = 0; i < 4; i++) { + _esp_apa102_send_byte(clockPinMask, dataPinMask, 0x00); + } +} + +static inline void _esp_apa102_append_additionial_cycles(uint32_t clockPinMask, uint32_t dataPinMask, uint32_t numBytes) { + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask); + + // we need to write some more clock cycles, because each led + // delays the data by one edge after inverting the clock + for (uint32_t i = 0; i < numBytes / 8 + ((numBytes / 4) % 2); i++) { + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask); + NOP; + NOP; + + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask); + NOP; + NOP; + } +} + +static inline void _esp_apa102_end_frame(uint32_t clockPinMask, uint32_t dataPinMask) { + for (uint32_t i = 0; i < 4; i++) { + _esp_apa102_send_byte(clockPinMask, dataPinMask, 0xFF); + } +} + +void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32_t numBytes) { + uint32_t clockPinMask, dataPinMask; + + clockPinMask = 1 << clockPin; + dataPinMask = 1 << dataPin; + + // start the frame + _esp_apa102_start_frame(clockPinMask, dataPinMask); + + // write pixels + _esp_apa102_send_colors(clockPinMask, dataPinMask, pixels, numBytes); + + // end the frame + _esp_apa102_append_additionial_cycles(clockPinMask, dataPinMask, numBytes); + _esp_apa102_end_frame(clockPinMask, dataPinMask); +} diff --git a/esp8266/espapa102.h b/esp8266/espapa102.h new file mode 100644 index 0000000000..82c92025d3 --- /dev/null +++ b/esp8266/espapa102.h @@ -0,0 +1,27 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Robert Foss, Daniel Busch + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32_t numBytes); diff --git a/esp8266/ets_alt_task.c b/esp8266/ets_alt_task.c index 91623f06df..62872affb9 100644 --- a/esp8266/ets_alt_task.c +++ b/esp8266/ets_alt_task.c @@ -5,6 +5,7 @@ #include <esp_sdk_ver.h> #include "etshal.h" #include "user_interface.h" +#include "ets_alt_task.h" // Use standard ets_task or alternative impl #define USE_ETS_TASK 0 @@ -107,7 +108,12 @@ bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) { #endif } +int ets_loop_iter_disable = 0; + bool ets_loop_iter(void) { + if (ets_loop_iter_disable) { + return false; + } //static unsigned cnt; bool progress = false; for (volatile struct task_entry *t = emu_tasks; t < &emu_tasks[MP_ARRAY_SIZE(emu_tasks)]; t++) { diff --git a/esp8266/ets_alt_task.h b/esp8266/ets_alt_task.h index c423995841..4b5ba26dbd 100644 --- a/esp8266/ets_alt_task.h +++ b/esp8266/ets_alt_task.h @@ -1 +1,2 @@ +extern int ets_loop_iter_disable; bool ets_loop_iter(void); diff --git a/esp8266/help.c b/esp8266/help.c index 3a4d6e83a2..5370ee71ea 100644 --- a/esp8266/help.c +++ b/esp8266/help.c @@ -37,7 +37,7 @@ STATIC const char *help_text = "Basic WiFi configuration:\n" "\n" "import network\n" -"sta_if = network.WLAN(network.STA_IF)\n" +"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n" "sta_if.scan() # Scan for available access points\n" "sta_if.connect(\"<AP_name>\", \"<password>\") # Connect to an AP\n" "sta_if.isconnected() # Check for successful connection\n" diff --git a/esp8266/main.c b/esp8266/main.c index 45ee85ac88..9cc955e44c 100644 --- a/esp8266/main.c +++ b/esp8266/main.c @@ -38,7 +38,7 @@ #include "gccollect.h" #include "user_interface.h" -STATIC char heap[24 * 1024]; +STATIC char heap[28 * 1024]; STATIC void mp_reset(void) { mp_stack_set_top((void*)0x40000000); @@ -58,7 +58,7 @@ STATIC void mp_reset(void) { MP_STATE_PORT(term_obj) = MP_OBJ_NULL; pin_init0(); #if MICROPY_MODULE_FROZEN - pyexec_frozen_module("_boot"); + pyexec_frozen_module("_boot.py"); pyexec_file("boot.py"); pyexec_file("main.py"); #endif diff --git a/esp8266/modesp.c b/esp8266/modesp.c index 44401d3a61..0c6cc423e1 100644 --- a/esp8266/modesp.c +++ b/esp8266/modesp.c @@ -27,13 +27,14 @@ #include <stdio.h> #include <string.h> #include <stdbool.h> -#include <errno.h> #include "py/nlr.h" #include "py/obj.h" #include "py/gc.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "py/mphal.h" +#include "drivers/dht/dht.h" #include "netutils.h" #include "queue.h" #include "ets_sys.h" @@ -43,6 +44,7 @@ #include "spi_flash.h" #include "mem.h" #include "espneopixel.h" +#include "espapa102.h" #include "modpyb.h" #define MODESP_ESPCONN (0) @@ -577,7 +579,7 @@ STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t len_or_buf_in) { if (alloc_buf) { m_del(byte, buf, len); } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? ETIMEDOUT : EIO))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO))); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read); @@ -594,7 +596,7 @@ STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, const mp_obj_t buf_in) { } nlr_raise(mp_obj_new_exception_arg1( &mp_type_OSError, - MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? ETIMEDOUT : EIO))); + MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO))); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write); @@ -606,7 +608,7 @@ STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) { } nlr_raise(mp_obj_new_exception_arg1( &mp_type_OSError, - MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? ETIMEDOUT : EIO))); + MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO))); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase); @@ -636,6 +638,16 @@ STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t is800k) } STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_); +STATIC mp_obj_t esp_apa102_write_(mp_obj_t clockPin, mp_obj_t dataPin, mp_obj_t buf) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + esp_apa102_write(mp_obj_get_pin_obj(clockPin)->phys_port, + mp_obj_get_pin_obj(dataPin)->phys_port, + (uint8_t*)bufinfo.buf, bufinfo.len); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_apa102_write_obj, esp_apa102_write_); + STATIC mp_obj_t esp_freemem() { return MP_OBJ_NEW_SMALL_INT(system_get_free_heap_size()); } @@ -679,6 +691,8 @@ STATIC const mp_map_elem_t esp_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&esp_getaddrinfo_obj }, #endif { MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write), (mp_obj_t)&esp_neopixel_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_apa102_write), (mp_obj_t)&esp_apa102_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_dht_readinto), (mp_obj_t)&dht_readinto_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_freemem), (mp_obj_t)&esp_freemem_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_meminfo), (mp_obj_t)&esp_meminfo_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj }, // TODO delete/rename/move elsewhere diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index c3c9494ac8..36872c9dff 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -30,10 +30,12 @@ #include "py/obj.h" #include "py/runtime.h" #include "extmod/machine_mem.h" +#include "extmod/machine_pulse.h" #include "extmod/machine_i2c.h" #include "modpyb.h" #include "modpybrtc.h" +#include "xtirq.h" #include "os_type.h" #include "osapi.h" #include "etshal.h" @@ -189,6 +191,25 @@ const mp_obj_type_t esp_timer_type = { .locals_dict = (mp_obj_t)&esp_timer_locals_dict, }; +// this bit is unused in the Xtensa PS register +#define ETS_LOOP_ITER_BIT (12) + +STATIC mp_obj_t machine_disable_irq(void) { + uint32_t state = disable_irq(); + state = (state & ~(1 << ETS_LOOP_ITER_BIT)) | (ets_loop_iter_disable << ETS_LOOP_ITER_BIT); + ets_loop_iter_disable = 1; + return mp_obj_new_int(state); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq); + +STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) { + uint32_t state = mp_obj_get_int(state_in); + ets_loop_iter_disable = (state >> ETS_LOOP_ITER_BIT) & 1; + enable_irq(state & ~(1 << ETS_LOOP_ITER_BIT)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq); + STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, @@ -201,6 +222,11 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + + { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) }, diff --git a/esp8266/modnetwork.c b/esp8266/modnetwork.c index 5e9273158c..c0763ce0eb 100644 --- a/esp8266/modnetwork.c +++ b/esp8266/modnetwork.c @@ -27,7 +27,6 @@ #include <stdio.h> #include <stdint.h> #include <string.h> -#include <errno.h> #include "py/nlr.h" #include "py/objlist.h" @@ -137,16 +136,25 @@ STATIC void esp_scan_cb(scaninfo *si, STATUS status) { return; } if (si->pbss && status == 0) { - struct bss_info *bs; - STAILQ_FOREACH(bs, si->pbss, next) { - mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); - t->items[0] = mp_obj_new_bytes(bs->ssid, strlen((char*)bs->ssid)); - t->items[1] = mp_obj_new_bytes(bs->bssid, sizeof(bs->bssid)); - t->items[2] = MP_OBJ_NEW_SMALL_INT(bs->channel); - t->items[3] = MP_OBJ_NEW_SMALL_INT(bs->rssi); - t->items[4] = MP_OBJ_NEW_SMALL_INT(bs->authmode); - t->items[5] = MP_OBJ_NEW_SMALL_INT(bs->is_hidden); - mp_obj_list_append(*esp_scan_list, MP_OBJ_FROM_PTR(t)); + // we need to catch any memory errors + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + struct bss_info *bs; + STAILQ_FOREACH(bs, si->pbss, next) { + mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); + t->items[0] = mp_obj_new_bytes(bs->ssid, strlen((char*)bs->ssid)); + t->items[1] = mp_obj_new_bytes(bs->bssid, sizeof(bs->bssid)); + t->items[2] = MP_OBJ_NEW_SMALL_INT(bs->channel); + t->items[3] = MP_OBJ_NEW_SMALL_INT(bs->rssi); + t->items[4] = MP_OBJ_NEW_SMALL_INT(bs->authmode); + t->items[5] = MP_OBJ_NEW_SMALL_INT(bs->is_hidden); + mp_obj_list_append(*esp_scan_list, MP_OBJ_FROM_PTR(t)); + } + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + // indicate error + *esp_scan_list = MP_OBJ_NULL; } } else { // indicate error @@ -156,14 +164,25 @@ STATIC void esp_scan_cb(scaninfo *si, STATUS status) { } STATIC mp_obj_t esp_scan(mp_obj_t self_in) { - if (wifi_get_opmode() == SOFTAP_MODE) { + require_if(self_in, STATION_IF); + if ((wifi_get_opmode() & STATION_MODE) == 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, - "scan unsupported in AP mode")); + "STA must be active")); } mp_obj_t list = mp_obj_new_list(0, NULL); esp_scan_list = &list; wifi_station_scan(NULL, (scan_done_cb_t)esp_scan_cb); - ETS_POLL_WHILE(esp_scan_list != NULL); + while (esp_scan_list != NULL) { + // our esp_scan_cb is called via ets_loop_iter so it's safe to set the + // esp_scan_list variable to NULL without disabling interrupts + if (MP_STATE_VM(mp_pending_exception) != NULL) { + esp_scan_list = NULL; + mp_obj_t obj = MP_STATE_VM(mp_pending_exception); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; + nlr_raise(obj); + } + ets_loop_iter(); + } if (list == MP_OBJ_NULL) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "scan failed")); } diff --git a/esp8266/modpybpin.c b/esp8266/modpybpin.c index 6b9e20268b..166d6f566f 100644 --- a/esp8266/modpybpin.c +++ b/esp8266/modpybpin.c @@ -36,6 +36,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/gc.h" +#include "py/mphal.h" #include "modpyb.h" #define GET_TRIGGER(phys_port) \ @@ -123,6 +124,34 @@ uint mp_obj_get_pin(mp_obj_t pin_in) { return mp_obj_get_pin_obj(pin_in)->phys_port; } +void mp_hal_pin_input(mp_hal_pin_obj_t pin_id) { + pin_mode[pin_id] = GPIO_MODE_INPUT; + if (pin_id == 16) { + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1); + WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1); + WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); // input + } else { + const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id]; + PIN_FUNC_SELECT(self->periph, self->func); + PIN_PULLUP_DIS(self->periph); + gpio_output_set(0, 0, 0, 1 << self->phys_port); + } +} + +void mp_hal_pin_output(mp_hal_pin_obj_t pin_id) { + pin_mode[pin_id] = GPIO_MODE_OUTPUT; + if (pin_id == 16) { + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1); + WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1); + WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | 1); // output + } else { + const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id]; + PIN_FUNC_SELECT(self->periph, self->func); + PIN_PULLUP_DIS(self->periph); + gpio_output_set(0, 0, 1 << self->phys_port, 0); + } +} + int pin_get(uint pin) { if (pin == 16) { return READ_PERI_REG(RTC_GPIO_IN_DATA) & 1; diff --git a/esp8266/modpybrtc.c b/esp8266/modpybrtc.c index e62dc88175..484d0d82fd 100644 --- a/esp8266/modpybrtc.c +++ b/esp8266/modpybrtc.c @@ -53,6 +53,9 @@ STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}}; uint32_t pyb_rtc_alarm0_wake; // see MACHINE_WAKE_xxx constants uint64_t pyb_rtc_alarm0_expiry; // in microseconds +// RTC overflow checking +STATIC uint32_t rtc_last_ticks; + void mp_hal_rtc_init(void) { uint32_t magic; @@ -64,7 +67,11 @@ void mp_hal_rtc_init(void) { int64_t delta = 0; system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal)); system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); + uint32_t len = 0; + system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); } + // system_get_rtc_time() is always 0 after reset/deepsleep + rtc_last_ticks = system_get_rtc_time(); // reset ALARM0 state pyb_rtc_alarm0_wake = 0; @@ -79,13 +86,11 @@ STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp return (mp_obj_t)&pyb_rtc_obj; } -STATIC uint64_t pyb_rtc_raw_us(uint64_t cal) { - return (system_get_rtc_time() * cal) >> 12; -}; - void pyb_rtc_set_us_since_2000(uint64_t nowus) { uint32_t cal = system_rtc_clock_cali_proc(); - int64_t delta = nowus - pyb_rtc_raw_us(cal); + // Save RTC ticks for overflow detection. + rtc_last_ticks = system_get_rtc_time(); + int64_t delta = nowus - (((uint64_t)rtc_last_ticks * cal) >> 12); // As the calibration value jitters quite a bit, to make the // clock at least somewhat practially usable, we need to store it @@ -96,11 +101,23 @@ void pyb_rtc_set_us_since_2000(uint64_t nowus) { uint64_t pyb_rtc_get_us_since_2000() { uint32_t cal; int64_t delta; + uint32_t rtc_ticks; system_rtc_mem_read(MEM_CAL_ADDR, &cal, sizeof(cal)); system_rtc_mem_read(MEM_DELTA_ADDR, &delta, sizeof(delta)); - return pyb_rtc_raw_us(cal) + delta; + // ESP-SDK system_get_rtc_time() only returns uint32 and therefore + // overflow about every 7:45h. Thus, we have to check for + // overflow and handle it. + rtc_ticks = system_get_rtc_time(); + if (rtc_ticks < rtc_last_ticks) { + // Adjust delta because of RTC overflow. + delta += (uint64_t)cal << 20; + system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta)); + } + rtc_last_ticks = rtc_ticks; + + return (((uint64_t)rtc_ticks * cal) >> 12) + delta; }; STATIC mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { @@ -145,20 +162,17 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_d STATIC mp_obj_t pyb_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { uint8_t rtcram[MEM_USER_MAXLEN]; uint32_t len; - uint32_t magic; if (n_args == 1) { - - system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); - if (magic != MEM_MAGIC) { - return mp_const_none; - } + // read RTC memory system_rtc_mem_read(MEM_USER_LEN_ADDR, &len, sizeof(len)); system_rtc_mem_read(MEM_USER_DATA_ADDR, rtcram, len + (4 - len % 4)); 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); @@ -167,8 +181,6 @@ STATIC mp_obj_t pyb_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) { "buffer too long")); } - magic = MEM_MAGIC; - system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic)); len = bufinfo.len; system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len)); diff --git a/esp8266/modpybspi.c b/esp8266/modpybspi.c index 1131e8ef6b..c2bcc33edc 100644 --- a/esp8266/modpybspi.c +++ b/esp8266/modpybspi.c @@ -27,7 +27,6 @@ #include <stdio.h> #include <stdint.h> #include <string.h> -#include <errno.h> #include "ets_sys.h" #include "etshal.h" @@ -124,6 +123,12 @@ STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj if (args[ARG_miso].u_obj != MP_OBJ_NULL) { self->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); } STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { diff --git a/esp8266/modpybuart.c b/esp8266/modpybuart.c index eefb38d998..5971ffecec 100644 --- a/esp8266/modpybuart.c +++ b/esp8266/modpybuart.c @@ -27,13 +27,13 @@ #include <stdio.h> #include <stdint.h> #include <string.h> -#include <errno.h> #include "ets_sys.h" #include "uart.h" #include "py/runtime.h" #include "py/stream.h" +#include "py/mperrno.h" #include "modpyb.h" // baudrate is currently fixed to this value @@ -136,7 +136,7 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i // wait for first char to become available if (!uart_rx_wait(self->timeout * 1000)) { - *errcode = EAGAIN; + *errcode = MP_EAGAIN; return MP_STREAM_ERROR; } @@ -173,7 +173,7 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t } STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { - *errcode = EINVAL; + *errcode = MP_EINVAL; return MP_STREAM_ERROR; } diff --git a/esp8266/moduos.c b/esp8266/moduos.c index d75062eaf7..74262d86b1 100644 --- a/esp8266/moduos.c +++ b/esp8266/moduos.c @@ -25,7 +25,6 @@ */ #include <string.h> -#include <errno.h> #include "py/mpconfig.h" #include "py/nlr.h" @@ -33,6 +32,7 @@ #include "py/objtuple.h" #include "py/objstr.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "extmod/misc.h" #include "genhdr/mpversion.h" #include "esp_mphal.h" @@ -74,12 +74,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); #if MICROPY_VFS_FAT mp_obj_t vfs_proxy_call(qstr method_name, mp_uint_t n_args, const mp_obj_t *args) { if (MP_STATE_PORT(fs_user_mount)[0] == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENODEV))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENODEV))); } mp_obj_t meth[n_args + 2]; mp_load_method(MP_STATE_PORT(fs_user_mount)[0], method_name, meth); - memcpy(meth + 2, args, n_args * sizeof(*args)); + if (args != NULL) { + memcpy(meth + 2, args, n_args * sizeof(*args)); + } return mp_call_method_n_kw(n_args, 0, meth); } @@ -93,10 +95,29 @@ STATIC mp_obj_t os_mkdir(mp_obj_t path_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir); +STATIC mp_obj_t os_chdir(mp_obj_t path_in) { + return vfs_proxy_call(MP_QSTR_chdir, 1, &path_in); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_chdir_obj, os_chdir); + +STATIC mp_obj_t os_getcwd(void) { + return vfs_proxy_call(MP_QSTR_getcwd, 0, NULL); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd); + STATIC mp_obj_t os_remove(mp_obj_t path_in) { return vfs_proxy_call(MP_QSTR_remove, 1, &path_in); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove); + +STATIC mp_obj_t os_rename(mp_obj_t path_old, mp_obj_t path_new) { + mp_obj_t args[2]; + args[0] = path_old; + args[1] = path_new; + return vfs_proxy_call(MP_QSTR_rename, 2, args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename); + #endif STATIC mp_obj_t os_urandom(mp_obj_t num) { @@ -117,6 +138,11 @@ STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify); +STATIC mp_obj_t os_stat(mp_obj_t path_in) { + return vfs_proxy_call(MP_QSTR_stat, 1, &path_in); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat); + STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) }, { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, @@ -129,7 +155,11 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) }, { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&os_listdir_obj) }, { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&os_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&os_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&os_getcwd_obj) }, { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&os_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&os_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&os_stat_obj) }, #endif }; diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index e2c7f57e22..544edc408f 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -4,6 +4,11 @@ #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C) #define MICROPY_ALLOC_PATH_MAX (128) +#define MICROPY_ALLOC_LEXER_INDENT_INIT (8) +#define MICROPY_ALLOC_PARSE_RULE_INIT (48) +#define MICROPY_ALLOC_PARSE_RULE_INC (8) +#define MICROPY_ALLOC_PARSE_RESULT_INC (8) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (64) #define MICROPY_EMIT_X64 (0) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) @@ -19,6 +24,7 @@ #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_MODULE_WEAK_LINKS (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_BYTEARRAY (1) @@ -32,14 +38,17 @@ #define MICROPY_PY_ARRAY (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1) #define MICROPY_PY_MATH (1) #define MICROPY_PY_CMATH (0) #define MICROPY_PY_IO (1) +#define MICROPY_PY_IO_FILEIO (1) #define MICROPY_PY_STRUCT (1) #define MICROPY_PY_SYS (1) #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_UERRNO (1) #define MICROPY_PY_UBINASCII (1) #define MICROPY_PY_UCTYPES (1) #define MICROPY_PY_UHASHLIB (1) @@ -51,6 +60,7 @@ #define MICROPY_PY_UZLIB (1) #define MICROPY_PY_LWIP (1) #define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_I2C (1) #define MICROPY_PY_WEBSOCKET (1) #define MICROPY_PY_WEBREPL (1) @@ -105,6 +115,9 @@ typedef uint32_t sys_prot_t; // for modlwip #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +#define mp_type_fileio fatfs_type_fileio +#define mp_type_textio fatfs_type_textio + // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \ @@ -135,6 +148,7 @@ extern const struct _mp_obj_module_t onewire_module; { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \ #define MP_STATE_PORT MP_STATE_VM diff --git a/esp8266/scripts/apa102.py b/esp8266/scripts/apa102.py new file mode 100644 index 0000000000..126448cc20 --- /dev/null +++ b/esp8266/scripts/apa102.py @@ -0,0 +1,28 @@ +# APA102 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Robert Foss, Daniel Busch + +from esp import apa102_write + +class APA102: + def __init__(self, clock_pin, data_pin, n): + self.clock_pin = clock_pin + self.data_pin = data_pin + self.n = n + self.buf = bytearray(n * 4) + + self.clock_pin.init(clock_pin.OUT) + self.data_pin.init(data_pin.OUT) + + def __setitem__(self, index, val): + r, g, b, brightness = val + self.buf[index * 4] = r + self.buf[index * 4 + 1] = g + self.buf[index * 4 + 2] = b + self.buf[index * 4 + 3] = brightness + + def __getitem__(self, index): + i = index * 4 + return self.buf[i], self.buf[i + 1], self.buf[i + 2], self.buf[i + 3] + + def write(self): + apa102_write(self.clock_pin, self.data_pin, self.buf) diff --git a/esp8266/scripts/dht.py b/esp8266/scripts/dht.py new file mode 100644 index 0000000000..9a69e7e07e --- /dev/null +++ b/esp8266/scripts/dht.py @@ -0,0 +1,32 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import esp + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + esp.dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: + raise Exception("checksum error") + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/esp8266/scripts/inisetup.py b/esp8266/scripts/inisetup.py index 93a05bd8a7..461690b162 100644 --- a/esp8266/scripts/inisetup.py +++ b/esp8266/scripts/inisetup.py @@ -40,7 +40,7 @@ def setup(): with open("/boot.py", "w") as f: f.write("""\ # This file is executed on every boot (including wake-boot from deepsleep) -import webrepl -webrepl.start() +#import webrepl +#webrepl.start() """) return vfs diff --git a/esp8266/scripts/neopixel.py b/esp8266/scripts/neopixel.py index 4818c74a3b..8aa0348680 100644 --- a/esp8266/scripts/neopixel.py +++ b/esp8266/scripts/neopixel.py @@ -8,7 +8,7 @@ class NeoPixel: self.pin = pin self.n = n self.buf = bytearray(n * 3) - self.pin.init(pin.OUT, pin.PULL_NONE) + self.pin.init(pin.OUT) def __setitem__(self, index, val): r, g, b = val @@ -20,5 +20,12 @@ class NeoPixel: i = index * 3 return self.buf[i + 1], self.buf[i], self.buf[i + 2] + def fill(self, color): + r, g, b = color + for i in range(len(self.buf) / 3): + self.buf[i * 3] = g + self.buf[i * 3 + 1] = r + self.buf[i * 3 + 2] = b + def write(self): neopixel_write(self.pin, self.buf, True) diff --git a/esp8266/scripts/ntptime.py b/esp8266/scripts/ntptime.py index 650cc2e85b..a97e08e60d 100644 --- a/esp8266/scripts/ntptime.py +++ b/esp8266/scripts/ntptime.py @@ -10,10 +10,12 @@ except: # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 NTP_DELTA = 3155673600 +host = "pool.ntp.org" + def time(): NTP_QUERY = bytearray(48) NTP_QUERY[0] = 0x1b - addr = socket.getaddrinfo('pool.ntp.org', 123)[0][-1] + addr = socket.getaddrinfo(host, 123)[0][-1] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(1) res = s.sendto(NTP_QUERY, addr) diff --git a/esp8266/scripts/onewire.py b/esp8266/scripts/onewire.py index 4980d0af5c..686616950a 100644 --- a/esp8266/scripts/onewire.py +++ b/esp8266/scripts/onewire.py @@ -13,7 +13,7 @@ class OneWire: def __init__(self, pin): self.pin = pin - self.pin.init(pin.OPEN_DRAIN, pin.PULL_NONE) + self.pin.init(pin.OPEN_DRAIN) def reset(self): return _ow.reset(self.pin) diff --git a/esp8266/scripts/port_diag.py b/esp8266/scripts/port_diag.py index fd7ee52d14..aa696b1abb 100644 --- a/esp8266/scripts/port_diag.py +++ b/esp8266/scripts/port_diag.py @@ -1,5 +1,7 @@ import esp import uctypes +import network +import lwip def main(): @@ -7,6 +9,7 @@ def main(): ROM = uctypes.bytearray_at(0x40200000, 16) fid = esp.flash_id() + print("FlashROM:") print("Flash ID: %x (Vendor: %x Device: %x)" % (fid, fid & 0xff, fid & 0xff00 | fid >> 16)) print("Flash bootloader data:") @@ -15,5 +18,14 @@ def main(): print("Byte @2: %02x" % ROM[2]) print("Byte @3: %02x (Flash size: %s Flash freq: %s)" % (ROM[3], SZ_MAP.get(ROM[3] >> 4, "?"), FREQ_MAP.get(ROM[3] & 0xf))) + print("\nNetworking:") + print("STA ifconfig:", network.WLAN(network.STA_IF).ifconfig()) + print("AP ifconfig:", network.WLAN(network.AP_IF).ifconfig()) + print("Free WiFi driver buffers of type:") + for i in range(5): + print("%d: %d" % (i, esp.esf_free_bufs(i))) + print("lwIP PCBs:") + lwip.print_pcbs() + main() diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py index 1a2c82277e..da3e70c595 100644 --- a/esp8266/scripts/webrepl.py +++ b/esp8266/scripts/webrepl.py @@ -10,7 +10,7 @@ listen_s = None client_s = None def setup_conn(port, accept_handler): - global listen_s, client_s + global listen_s listen_s = socket.socket() listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -19,11 +19,13 @@ def setup_conn(port, accept_handler): listen_s.bind(addr) listen_s.listen(1) - listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) + if accept_handler: + listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler) for i in (network.AP_IF, network.STA_IF): iface = network.WLAN(i) if iface.active(): print("WebREPL daemon started on ws://%s:%d" % (iface.ifconfig()[0], port)) + return listen_s def accept_conn(listen_sock): @@ -49,14 +51,25 @@ def stop(): listen_s.close() -def start(port=8266): +def start(port=8266, password=None): stop() - try: - import port_config - _webrepl.password(port_config.WEBREPL_PASS) + if password is None: + try: + import port_config + _webrepl.password(port_config.WEBREPL_PASS) + setup_conn(port, accept_conn) + print("Started webrepl in normal mode") + except: + import webrepl_setup + setup_conn(port, webrepl_setup.handle_conn) + print("Started webrepl in setup mode") + else: + _webrepl.password(password) setup_conn(port, accept_conn) print("Started webrepl in normal mode") - except: - import webrepl_setup - setup_conn(port, webrepl_setup.handle_conn) - print("Started webrepl in setup mode") + + +def start_foreground(port=8266): + stop() + s = setup_conn(port, None) + accept_conn(s) diff --git a/esp8266/scripts/webrepl_setup.py b/esp8266/scripts/webrepl_setup.py index 7c4068750c..d0bf8465d5 100644 --- a/esp8266/scripts/webrepl_setup.py +++ b/esp8266/scripts/webrepl_setup.py @@ -26,7 +26,7 @@ def getpass(stream, prompt): stream.write("\r\n") return passwd passwd += c -# stream.write("*") + stream.write("*") def handle_conn(listen_sock): cl, remote_addr = listen_sock.accept() @@ -60,6 +60,9 @@ some boards, you may need to press reset button or reconnect power.\r if len(passwd1) < 4: ws.write("Password too short\r\n") continue + elif len(passwd1) > 9: + ws.write("Password too long\r\n") + continue passwd2 = getpass(ws, "Confirm password: ") if passwd1 == passwd2: break diff --git a/esp8266/uart.c b/esp8266/uart.c index 573f0cb072..1c317a1cb6 100644 --- a/esp8266/uart.c +++ b/esp8266/uart.c @@ -19,6 +19,9 @@ #include "user_interface.h" #include "esp_mphal.h" +// seems that this is missing in the Espressif SDK +#define FUNC_U0RXD 0 + #define UART_REPL UART0 // UartDev is defined and initialized in rom code. @@ -53,7 +56,7 @@ static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) { ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, NULL); PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD); } uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate)); diff --git a/esp8266/xtirq.h b/esp8266/xtirq.h new file mode 100644 index 0000000000..856ff075ac --- /dev/null +++ b/esp8266/xtirq.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_ESP8266_XTIRQ_H__ +#define __MICROPY_INCLUDED_ESP8266_XTIRQ_H__ + +#include <stdint.h> + +// returns the value of "intlevel" from the PS register +static inline uint32_t query_irq(void) { + uint32_t ps; + __asm__ volatile("rsr %0, ps" : "=a" (ps)); + return ps & 0xf; +} + +// irqs with a priority value lower or equal to "intlevel" will be disabled +// "intlevel" should be between 0 and 15 inclusive, and should be an integer +static inline uint32_t raise_irq_pri(uint32_t intlevel) { + uint32_t old_ps; + __asm__ volatile ("rsil %0, %1" : "=a" (old_ps) : "I" (intlevel)); + return old_ps; +} + +// "ps" should be the value returned from raise_irq_pri +static inline void restore_irq_pri(uint32_t ps) { + __asm__ volatile ("wsr %0, ps; rsync" :: "a" (ps)); +} + +static inline uint32_t disable_irq(void) { + return raise_irq_pri(15); +} + +static inline void enable_irq(uint32_t irq_state) { + restore_irq_pri(irq_state); +} + +#endif // __MICROPY_INCLUDED_ESP8266_XTIRQ_H__ diff --git a/extmod/fsusermount.c b/extmod/fsusermount.c index 8f789ca033..9ddc98f3dd 100644 --- a/extmod/fsusermount.c +++ b/extmod/fsusermount.c @@ -32,7 +32,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "lib/fatfs/ff.h" -#include "fsusermount.h" +#include "extmod/fsusermount.h" fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs) { static const mp_arg_t allowed_args[] = { diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index e3bdb36925..ceddf0730e 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -48,7 +48,7 @@ STATIC void mp_hal_i2c_delay(machine_i2c_obj_t *self) { } STATIC void mp_hal_i2c_scl_low(machine_i2c_obj_t *self) { - mp_hal_pin_low(self->scl); + mp_hal_pin_od_low(self->scl); } STATIC void mp_hal_i2c_scl_release(machine_i2c_obj_t *self) { @@ -56,7 +56,7 @@ STATIC void mp_hal_i2c_scl_release(machine_i2c_obj_t *self) { } STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) { - mp_hal_pin_low(self->sda); + mp_hal_pin_od_low(self->sda); } STATIC void mp_hal_i2c_sda_release(machine_i2c_obj_t *self) { @@ -91,8 +91,8 @@ STATIC void mp_hal_i2c_init(machine_i2c_obj_t *self, uint32_t freq) { if (self->us_delay == 0) { self->us_delay = 1; } - mp_hal_pin_config_od(self->scl); - mp_hal_pin_config_od(self->sda); + mp_hal_pin_open_drain(self->scl); + mp_hal_pin_open_drain(self->sda); mp_hal_i2c_stop(self); } diff --git a/extmod/machine_pulse.c b/extmod/machine_pulse.c new file mode 100644 index 0000000000..8c8bff510c --- /dev/null +++ b/extmod/machine_pulse.c @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/machine_pulse.h" + +#if MICROPY_PY_MACHINE_PULSE + +mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { + mp_uint_t start = mp_hal_ticks_us(); + while (mp_hal_pin_read(pin) != pulse_level) { + if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { + return (mp_uint_t)-1; + } + } + start = mp_hal_ticks_us(); + while (mp_hal_pin_read(pin) == pulse_level) { + if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { + return (mp_uint_t)-1; + } + } + return mp_hal_ticks_us() - start; +} + +STATIC mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) { + mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(args[0]); + int level = 0; + if (mp_obj_is_true(args[1])) { + level = 1; + } + mp_uint_t timeout_us = 1000000; + if (n_args > 2) { + timeout_us = mp_obj_get_int(args[2]); + } + mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us); + if (us == (mp_uint_t)-1) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); + } + return mp_obj_new_int(us); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj, 2, 3, machine_time_pulse_us_); + +#endif diff --git a/extmod/machine_pulse.h b/extmod/machine_pulse.h new file mode 100644 index 0000000000..3d5d81c073 --- /dev/null +++ b/extmod/machine_pulse.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H__ +#define __MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H__ + +#include "py/obj.h" +#include "py/mphal.h" + +mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us); + +MP_DECLARE_CONST_FUN_OBJ(machine_time_pulse_us_obj); + +#endif // __MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H__ diff --git a/extmod/misc.h b/extmod/misc.h index 39bfd5ecb5..634ea924d0 100644 --- a/extmod/misc.h +++ b/extmod/misc.h @@ -34,6 +34,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_uos_dupterm_obj); #if MICROPY_PY_OS_DUPTERM void mp_uos_dupterm_tx_strn(const char *str, size_t len); +void mp_uos_deactivate(const char *msg, mp_obj_t exc); #else #define mp_uos_dupterm_tx_strn(s, l) #endif diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 090e1005a8..cb7cc6596f 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -26,13 +26,13 @@ */ #include <string.h> -#include <errno.h> #include <stdio.h> #include "py/nlr.h" #include "py/objlist.h" #include "py/runtime.h" #include "py/stream.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "netutils.h" @@ -172,45 +172,45 @@ STATIC const mp_obj_type_t lwip_slip_type = { // investigate in more detail. #if LWIP_VERSION < 0x01040100 static const int error_lookup_table[] = { - 0, /* ERR_OK 0 No error, everything OK. */ - ENOMEM, /* ERR_MEM -1 Out of memory error. */ - ENOBUFS, /* ERR_BUF -2 Buffer error. */ - EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ - EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ - EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ - EINVAL, /* ERR_VAL -6 Illegal value. */ - EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ - - ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */ - ECONNRESET, /* ERR_RST -9 Connection reset. */ - ENOTCONN, /* ERR_CLSD -10 Connection closed. */ - ENOTCONN, /* ERR_CONN -11 Not connected. */ - EIO, /* ERR_ARG -12 Illegal argument. */ - EADDRINUSE, /* ERR_USE -13 Address in use. */ - -1, /* ERR_IF -14 Low-level netif error */ - EALREADY, /* ERR_ISCONN -15 Already connected. */ - EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ + 0, /* ERR_OK 0 No error, everything OK. */ + MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ + MP_ENOBUFS, /* ERR_BUF -2 Buffer error. */ + MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + MP_EINVAL, /* ERR_VAL -6 Illegal value. */ + MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + + MP_ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */ + MP_ECONNRESET, /* ERR_RST -9 Connection reset. */ + MP_ENOTCONN, /* ERR_CLSD -10 Connection closed. */ + MP_ENOTCONN, /* ERR_CONN -11 Not connected. */ + MP_EIO, /* ERR_ARG -12 Illegal argument. */ + MP_EADDRINUSE, /* ERR_USE -13 Address in use. */ + -1, /* ERR_IF -14 Low-level netif error */ + MP_EALREADY, /* ERR_ISCONN -15 Already connected. */ + MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ }; #else static const int error_lookup_table[] = { - 0, /* ERR_OK 0 No error, everything OK. */ - ENOMEM, /* ERR_MEM -1 Out of memory error. */ - ENOBUFS, /* ERR_BUF -2 Buffer error. */ - EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ - EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ - EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ - EINVAL, /* ERR_VAL -6 Illegal value. */ - EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ - - EADDRINUSE, /* ERR_USE -8 Address in use. */ - EALREADY, /* ERR_ISCONN -9 Already connected. */ - ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ - ECONNRESET, /* ERR_RST -11 Connection reset. */ - ENOTCONN, /* ERR_CLSD -12 Connection closed. */ - ENOTCONN, /* ERR_CONN -13 Not connected. */ - EIO, /* ERR_ARG -14 Illegal argument. */ - -1, /* ERR_IF -15 Low-level netif error */ - EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ + 0, /* ERR_OK 0 No error, everything OK. */ + MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ + MP_ENOBUFS, /* ERR_BUF -2 Buffer error. */ + MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + MP_EINVAL, /* ERR_VAL -6 Illegal value. */ + MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + + MP_EADDRINUSE, /* ERR_USE -8 Address in use. */ + MP_EALREADY, /* ERR_ISCONN -9 Already connected. */ + MP_ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ + MP_ECONNRESET, /* ERR_RST -11 Connection reset. */ + MP_ENOTCONN, /* ERR_CLSD -12 Connection closed. */ + MP_ENOTCONN, /* ERR_CONN -13 Not connected. */ + MP_EIO, /* ERR_ARG -14 Illegal argument. */ + -1, /* ERR_IF -15 Low-level netif error */ + MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ }; #endif @@ -311,6 +311,17 @@ STATIC err_t _lwip_tcp_recv_unaccepted(void *arg, struct tcp_pcb *pcb, struct pb return ERR_BUF; } +// "Poll" (idle) callback to be called ASAP after accept callback +// to execute Python callback function, as it can't be executed +// from accept callback itself. +STATIC err_t _lwip_tcp_accept_finished(void *arg, struct tcp_pcb *pcb) +{ + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + tcp_poll(pcb, NULL, 0); + exec_user_callback(socket); + return ERR_OK; +} + // Callback for incoming tcp connections. STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; @@ -323,7 +334,12 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { return ERR_BUF; } else { socket->incoming.connection = newpcb; - exec_user_callback(socket); + if (socket->callback != MP_OBJ_NULL) { + // Schedule accept callback to be called when lwIP is done + // with processing this incoming connection on its side and + // is idle. + tcp_poll(newpcb, _lwip_tcp_accept_finished, 1); + } return ERR_OK; } } @@ -363,7 +379,7 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui // FIXME: maybe PBUF_ROM? struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (p == NULL) { - *_errno = ENOMEM; + *_errno = MP_ENOMEM; return -1; } @@ -401,7 +417,7 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ if (socket->incoming.pbuf != NULL) break; } if (socket->incoming.pbuf == NULL) { - *_errno = ETIMEDOUT; + *_errno = MP_ETIMEDOUT; return -1; } } else { @@ -444,7 +460,7 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui if (available == 0) { // Non-blocking socket if (socket->timeout == 0) { - *_errno = EAGAIN; + *_errno = MP_EAGAIN; return MP_STREAM_ERROR; } @@ -457,7 +473,7 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui // Avoid sending too small packets, so wait until at least 16 bytes available while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) { if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { - *_errno = ETIMEDOUT; + *_errno = MP_ETIMEDOUT; return MP_STREAM_ERROR; } poll_sockets(); @@ -491,14 +507,14 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ if (socket->state == STATE_PEER_CLOSED) { return 0; } - *_errno = EAGAIN; + *_errno = MP_EAGAIN; return -1; } mp_uint_t start = mp_hal_ticks_ms(); while (socket->state == STATE_CONNECTED && socket->incoming.pbuf == NULL) { if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { - *_errno = ETIMEDOUT; + *_errno = MP_ETIMEDOUT; return -1; } poll_sockets(); @@ -570,11 +586,11 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args case MOD_NETWORK_SOCK_STREAM: socket->pcb.tcp = tcp_new(); break; case MOD_NETWORK_SOCK_DGRAM: socket->pcb.udp = udp_new(); break; //case MOD_NETWORK_SOCK_RAW: socket->pcb.raw = raw_new(); break; - default: nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); + default: nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL))); } if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOMEM))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM))); } switch (socket->type) { @@ -670,15 +686,15 @@ STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { mp_int_t backlog = mp_obj_get_int(backlog_in); if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF))); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EOPNOTSUPP))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP))); } struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog); if (new_pcb == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOMEM))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM))); } socket->pcb.tcp = new_pcb; tcp_accept(new_pcb, _lwip_tcp_accept); @@ -691,15 +707,15 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF))); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EOPNOTSUPP))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP))); } // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = socket->pcb.tcp; if (listener->state != LISTEN) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL))); } // accept incoming connection @@ -710,7 +726,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { if (socket->incoming.connection != NULL) break; } if (socket->incoming.connection == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); } } else { while (socket->incoming.connection == NULL) { @@ -757,7 +773,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF))); } // get address @@ -772,9 +788,9 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { case MOD_NETWORK_SOCK_STREAM: { if (socket->state != STATE_NEW) { if (socket->state == STATE_CONNECTED) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EALREADY))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EALREADY))); } else { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINPROGRESS))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINPROGRESS))); } } // Register our recieve callback. @@ -794,7 +810,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { if (socket->state != STATE_CONNECTING) break; } if (socket->state == STATE_CONNECTING) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); } } else { while (socket->state == STATE_CONNECTING) { @@ -982,7 +998,7 @@ STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) { // most useful behavior is: check whether we will be able to send all of input // data without EAGAIN, and if won't be, raise it without sending any. if (bufinfo.len > tcp_sndbuf(socket->pcb.tcp)) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EAGAIN))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EAGAIN))); } } // TODO: In CPython3.5, socket timeout should apply to the diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c index 82f910b0e7..3cceb991f1 100644 --- a/extmod/modubinascii.c +++ b/extmod/modubinascii.c @@ -31,7 +31,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/binary.h" -#include "modubinascii.h" +#include "extmod/modubinascii.h" mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) { diff --git a/extmod/moduos_dupterm.c b/extmod/moduos_dupterm.c index 41b8b3c81e..4c9f9e4940 100644 --- a/extmod/moduos_dupterm.c +++ b/extmod/moduos_dupterm.c @@ -31,9 +31,20 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/objtuple.h" +#include "py/stream.h" #if MICROPY_PY_OS_DUPTERM +void mp_uos_deactivate(const char *msg, mp_obj_t exc) { + mp_obj_t term = MP_STATE_PORT(term_obj); + MP_STATE_PORT(term_obj) = NULL; + mp_printf(&mp_plat_print, msg); + if (exc != MP_OBJ_NULL) { + mp_obj_print_exception(&mp_plat_print, exc); + } + mp_stream_close(term); +} + void mp_uos_dupterm_tx_strn(const char *str, size_t len) { if (MP_STATE_PORT(term_obj) != MP_OBJ_NULL) { nlr_buf_t nlr; @@ -44,9 +55,7 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) { mp_call_method_n_kw(1, 0, write_m); nlr_pop(); } else { - MP_STATE_PORT(term_obj) = NULL; - mp_printf(&mp_plat_print, "dupterm: Exception in write() method, deactivating: "); - mp_obj_print_exception(&mp_plat_print, nlr.ret_val); + mp_uos_deactivate("dupterm: Exception in write() method, deactivating: ", nlr.ret_val); } } } diff --git a/extmod/modussl.c b/extmod/modussl.c index 51f4fead81..567033cf48 100644 --- a/extmod/modussl.c +++ b/extmod/modussl.c @@ -78,12 +78,12 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, bool server_side) { STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; - mp_obj_ssl_socket_t *self = self_in; + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "<_SSLSocket %p>", self->ssl_sock); } STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { - mp_obj_ssl_socket_t *o = o_in; + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); while (o->bytes_left == 0) { mp_int_t r = ssl_read(o->ssl_sock, &o->buf); @@ -113,7 +113,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc } STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { - mp_obj_ssl_socket_t *o = o_in; + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); mp_int_t r = ssl_write(o->ssl_sock, buf, size); if (r < 0) { *errcode = r; @@ -123,7 +123,7 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in } STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_ssl_socket_t *self = self_in; + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); ssl_free(self->ssl_sock); ssl_ctx_free(self->ssl_ctx); @@ -133,13 +133,13 @@ STATIC mp_obj_t socket_close(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); -STATIC const mp_map_elem_t ussl_socket_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, - { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj }, +STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table); @@ -157,10 +157,10 @@ STATIC const mp_obj_type_t ussl_socket_type = { .getiter = NULL, .iternext = NULL, .stream_p = &ussl_socket_stream_p, - .locals_dict = (mp_obj_t)&ussl_socket_locals_dict, + .locals_dict = (void*)&ussl_socket_locals_dict, }; -STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // TODO: Implement more args static const mp_arg_t allowed_args[] = { { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, @@ -175,13 +175,13 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args, mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); - return socket_new(sock, args.server_side.u_bool); + return MP_OBJ_FROM_PTR(socket_new(sock, args.server_side.u_bool)); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); -STATIC const mp_map_elem_t mp_module_ssl_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ussl) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_wrap_socket), (mp_obj_t)&mod_ssl_wrap_socket_obj }, +STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) }, + { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table); @@ -195,6 +195,8 @@ const mp_obj_module_t mp_module_ussl = { // These functions might be split to stream_posix.c. They are referenced by // axtls os_port.h . +ssize_t mp_stream_posix_write(void *sock_obj, const void *buf, size_t len); +ssize_t mp_stream_posix_read(void *sock_obj, void *buf, size_t len); int mp_stream_errno; diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index c160abea2f..8ecab922aa 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -250,8 +250,8 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int DEBUG_printf("webrepl: Writing %lu bytes to file\n", buf_sz); int err; - mp_uint_t res = mp_stream_writeall(self->cur_file, filebuf, buf_sz, &err); - if(res == MP_STREAM_ERROR) { + mp_uint_t res = mp_stream_write_exactly(self->cur_file, filebuf, buf_sz, &err); + if (err != 0 || res != buf_sz) { assert(0); } @@ -284,6 +284,13 @@ STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size return stream_p->write(self->sock, buf, size, errcode); } +STATIC mp_obj_t webrepl_close(mp_obj_t self_in) { + mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(self_in); + // TODO: This is a place to do cleanup + return mp_stream_close(self->sock); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_close_obj, webrepl_close); + STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) { mp_uint_t len; const char *passwd = mp_obj_str_get_data(passwd_in, &len); @@ -297,6 +304,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_set_password_obj, webrepl_set_password) STATIC const mp_map_elem_t webrepl_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&webrepl_close_obj }, }; STATIC MP_DEFINE_CONST_DICT(webrepl_locals_dict, webrepl_locals_dict_table); diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c index 344933ded3..fc5e29a05e 100644 --- a/extmod/modwebsocket.c +++ b/extmod/modwebsocket.c @@ -240,9 +240,9 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si mp_call_method_n_kw(1, 0, dest); } - mp_uint_t out_sz = mp_stream_writeall(self->sock, header, hdr_sz, errcode); - if (out_sz != MP_STREAM_ERROR) { - out_sz = mp_stream_writeall(self->sock, buf, size, errcode); + mp_uint_t out_sz = mp_stream_write_exactly(self->sock, header, hdr_sz, errcode); + if (*errcode == 0) { + out_sz = mp_stream_write_exactly(self->sock, buf, size, errcode); } if (self->opts & BLOCKING_WRITE) { @@ -250,6 +250,9 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si mp_call_method_n_kw(1, 0, dest); } + if (*errcode != 0) { + return MP_STREAM_ERROR; + } return out_sz; } @@ -269,10 +272,19 @@ STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t } } +STATIC mp_obj_t websocket_close(mp_obj_t self_in) { + mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); + // TODO: Send close signaling to the other side, otherwise it's + // abrupt close (connection abort). + return mp_stream_close(self->sock); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(websocket_close_obj, websocket_close); + STATIC const mp_map_elem_t websocket_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&mp_stream_ioctl_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&websocket_close_obj }, }; STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table); diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index c52adfbe08..a4a81370f9 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -28,12 +28,14 @@ #include "py/mpconfig.h" #if MICROPY_VFS_FAT +#include <string.h> #include "py/nlr.h" #include "py/runtime.h" #include "lib/fatfs/ff.h" #include "lib/fatfs/diskio.h" #include "extmod/vfs_fat_file.h" -#include "fsusermount.h" +#include "extmod/fsusermount.h" +#include "timeutils.h" #define mp_obj_fat_vfs_t fs_user_mount_t @@ -79,12 +81,11 @@ STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) { const char *path = mp_obj_str_get_str(path_in); // TODO check that path is actually a file before trying to unlink it FRESULT res = f_unlink(path); - switch (res) { - case FR_OK: - return mp_const_none; - default: - // TODO: standard errno's - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing file '%s'", path)); + if (res == FR_OK) { + return mp_const_none; + } else { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_remove_obj, fat_vfs_remove); @@ -94,11 +95,11 @@ STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_ const char *old_path = mp_obj_str_get_str(path_in); const char *new_path = mp_obj_str_get_str(path_out); FRESULT res = f_rename(old_path, new_path); - switch (res) { - case FR_OK: - return mp_const_none; - default: - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error renaming file '%s' to '%s'", old_path, new_path)); + if (res == FR_OK) { + return mp_const_none; + } else { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } } @@ -108,25 +109,149 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) { (void)vfs_in; const char *path = mp_obj_str_get_str(path_o); FRESULT res = f_mkdir(path); - switch (res) { - case FR_OK: - return mp_const_none; - case FR_EXIST: - // TODO should be FileExistsError - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "File exists: '%s'", path)); - default: - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error creating directory '%s'", path)); + if (res == FR_OK) { + return mp_const_none; + } else { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir); +/// Change current directory. +STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) { + (void)vfs_in; + const char *path; + path = mp_obj_str_get_str(path_in); + + FRESULT res = f_chdrive(path); + + if (res == FR_OK) { + res = f_chdir(path); + } + + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir); + +/// Get the current directory. +STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { + (void)vfs_in; + char buf[MICROPY_ALLOC_PATH_MAX + 1]; + FRESULT res = f_getcwd(buf, sizeof buf); + + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + } + + return mp_obj_new_str(buf, strlen(buf), false); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); + +// Checks for path equality, ignoring trailing slashes: +// path_equal(/, /) -> true +// second argument must be in canonical form (meaning no trailing slash, unless it's just /) +STATIC bool path_equal(const char *path, const char *path_canonical) { + while (*path_canonical != '\0' && *path == *path_canonical) { + ++path; + ++path_canonical; + } + if (*path_canonical != '\0') { + return false; + } + while (*path == '/') { + ++path; + } + return *path == '\0'; +} + +/// \function stat(path) +/// Get the status of a file or directory. +STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { + (void)vfs_in; + const char *path = mp_obj_str_get_str(path_in); + + FILINFO fno; +#if _USE_LFN + fno.lfname = NULL; + fno.lfsize = 0; +#endif + FRESULT res; + + if (path_equal(path, "/")) { + // stat root directory + fno.fsize = 0; + fno.fdate = 0; + fno.ftime = 0; + fno.fattrib = AM_DIR; + } else { + res = FR_NO_PATH; + for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; + if (vfs != NULL && path_equal(path, vfs->str)) { + // stat mounted device directory + fno.fsize = 0; + fno.fdate = 0; + fno.ftime = 0; + fno.fattrib = AM_DIR; + res = FR_OK; + } + } + if (res == FR_NO_PATH) { + // stat normal file + res = f_stat(path, &fno); + } + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + } + } + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + mp_int_t mode = 0; + if (fno.fattrib & AM_DIR) { + mode |= 0x4000; // stat.S_IFDIR + } else { + mode |= 0x8000; // stat.S_IFREG + } + mp_int_t seconds = timeutils_seconds_since_2000( + 1980 + ((fno.fdate >> 9) & 0x7f), + (fno.fdate >> 5) & 0x0f, + fno.fdate & 0x1f, + (fno.ftime >> 11) & 0x1f, + (fno.ftime >> 5) & 0x3f, + 2 * (fno.ftime & 0x1f) + ); + t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode + t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino + t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev + t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink + t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid + t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid + t->items[6] = MP_OBJ_NEW_SMALL_INT(fno.fsize); // st_size + t->items[7] = MP_OBJ_NEW_SMALL_INT(seconds); // st_atime + t->items[8] = MP_OBJ_NEW_SMALL_INT(seconds); // st_mtime + t->items[9] = MP_OBJ_NEW_SMALL_INT(seconds); // st_ctime + + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat); + STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) }, { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&fat_vfs_listdir_obj) }, { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&fat_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&fat_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&fat_vfs_getcwd_obj) }, { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&fat_vfs_remove_obj) }, { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) }, }; STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c index 145b624c2b..23fe4be88d 100644 --- a/extmod/vfs_fat_misc.c +++ b/extmod/vfs_fat_misc.c @@ -35,7 +35,7 @@ #include "lib/fatfs/ff.h" #include "lib/fatfs/diskio.h" #include "extmod/vfs_fat_file.h" -#include "fsusermount.h" +#include "extmod/fsusermount.h" #include "py/lexer.h" #if _USE_LFN @@ -54,8 +54,9 @@ mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type) { res = f_opendir(&dir, path); /* Open the directory */ if (res != FR_OK) { - // TODO should be mp_type_FileNotFoundError - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "No such file or directory: '%s'", path)); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + } mp_obj_t dir_list = mp_obj_new_list(0, NULL); diff --git a/extmod/virtpin.c b/extmod/virtpin.c new file mode 100644 index 0000000000..a5817ab4d0 --- /dev/null +++ b/extmod/virtpin.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "extmod/virtpin.h" + +int mp_virtual_pin_read(mp_obj_t pin) { + mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin); + mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->stream_p; + return pin_p->ioctl(pin, MP_PIN_READ, 0, NULL); +} + +void mp_virtual_pin_write(mp_obj_t pin, int value) { + mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin); + mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->stream_p; + pin_p->ioctl(pin, MP_PIN_WRITE, value, NULL); +} diff --git a/extmod/virtpin.h b/extmod/virtpin.h new file mode 100644 index 0000000000..3821f9dec5 --- /dev/null +++ b/extmod/virtpin.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +#define MP_PIN_READ (1) +#define MP_PIN_WRITE (2) +#define MP_PIN_INPUT (3) +#define MP_PIN_OUTPUT (4) + +// Pin protocol +typedef struct _mp_pin_p_t { + mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); +} mp_pin_p_t; + +int mp_virtual_pin_read(mp_obj_t pin); +void mp_virtual_pin_write(mp_obj_t pin, int value); diff --git a/lib/timeutils/timeutils.c b/lib/timeutils/timeutils.c index 518f570090..19d3ddbdd3 100644 --- a/lib/timeutils/timeutils.c +++ b/lib/timeutils/timeutils.c @@ -158,8 +158,8 @@ mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, + (year - 2000) * 31536000; } -mp_uint_t timeutils_mktime(mp_uint_t year, mp_uint_t month, mp_uint_t mday, - mp_uint_t hours, mp_uint_t minutes, mp_uint_t seconds) { +mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { // Normalize the tuple. This allows things like: // @@ -204,7 +204,7 @@ mp_uint_t timeutils_mktime(mp_uint_t year, mp_uint_t month, mp_uint_t mday, } mday += timeutils_days_in_month(year, month); } - while (mday > timeutils_days_in_month(year, month)) { + while ((mp_uint_t)mday > timeutils_days_in_month(year, month)) { mday -= timeutils_days_in_month(year, month); if (++month == 13) { month = 1; diff --git a/lib/timeutils/timeutils.h b/lib/timeutils/timeutils.h index d6e3536ad7..c3f1fc2db1 100644 --- a/lib/timeutils/timeutils.h +++ b/lib/timeutils/timeutils.h @@ -49,7 +49,7 @@ void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second); -mp_uint_t timeutils_mktime(mp_uint_t year, mp_uint_t month, mp_uint_t mday, - mp_uint_t hours, mp_uint_t minutes, mp_uint_t seconds); +mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds); #endif // __MICROPY_INCLUDED_LIB_TIMEUTILS_H__ diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 952ff52184..4393d00ff0 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -52,7 +52,7 @@ STATIC void stderr_print_strn(void *env, const char *str, mp_uint_t len) { STATIC const mp_print_t mp_stderr_print = {NULL, stderr_print_strn}; -STATIC int compile_and_save(const char *file, const char *output_file) { +STATIC int compile_and_save(const char *file, const char *output_file, const char *source_file) { mp_lexer_t *lex = mp_lexer_new_from_file(file); if (lex == NULL) { printf("could not open file '%s' for reading\n", file); @@ -61,7 +61,12 @@ STATIC int compile_and_save(const char *file, const char *output_file) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - qstr source_name = lex->source_name; + qstr source_name; + if (source_file == NULL) { + source_name = lex->source_name; + } else { + source_name = qstr_from_str(source_file); + } #if MICROPY_PY___FILE__ if (input_kind == MP_PARSE_FILE_INPUT) { @@ -97,7 +102,8 @@ STATIC int usage(char **argv) { printf( "usage: %s [<opts>] [-X <implopt>] <input filename>\n" "Options:\n" -"-o : output file for compiled bytecode\n" +"-o : output file for compiled bytecode (defaults to input with .mpy extension)\n" +"-s : source filename to embed in the compiled bytecode (defaults to input file)\n" "-v : verbose (trace various operations); can be multiple\n" "-O[N] : apply bytecode optimizations of level N\n" "\n" @@ -189,6 +195,7 @@ MP_NOINLINE int main_(int argc, char **argv) { const char *input_file = NULL; const char *output_file = NULL; + const char *source_file = NULL; // parse main options for (int a = 1; a < argc; a++) { @@ -210,6 +217,12 @@ MP_NOINLINE int main_(int argc, char **argv) { } a += 1; output_file = argv[a]; + } else if (strcmp(argv[a], "-s") == 0) { + if (a + 1 >= argc) { + exit(usage(argv)); + } + a += 1; + source_file = argv[a]; } else if (strncmp(argv[a], "-msmall-int-bits=", sizeof("-msmall-int-bits=") - 1) == 0) { char *end; mp_dynamic_compiler.small_int_bits = @@ -243,7 +256,7 @@ MP_NOINLINE int main_(int argc, char **argv) { exit(1); } - int ret = compile_and_save(input_file, output_file); + int ret = compile_and_save(input_file, output_file, source_file); #if MICROPY_PY_MICROPYTHON_MEM_INFO if (mp_verbose_flag) { diff --git a/py/builtin.h b/py/builtin.h index 9d6e424091..5d79d2835e 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -98,6 +98,7 @@ extern const mp_obj_module_t mp_module_gc; extern const mp_obj_dict_t mp_module_builtins_globals; // extmod modules +extern const mp_obj_module_t mp_module_uerrno; extern const mp_obj_module_t mp_module_uctypes; extern const mp_obj_module_t mp_module_uzlib; extern const mp_obj_module_t mp_module_ujson; diff --git a/py/builtinimport.c b/py/builtinimport.c index 0e4dce6430..d3670858e5 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -60,22 +60,34 @@ bool mp_obj_is_package(mp_obj_t module) { return dest[0] != MP_OBJ_NULL; } +// Stat either frozen or normal module by a given path +// (whatever is available, if at all). +STATIC mp_import_stat_t mp_import_stat_any(const char *path) { + #if MICROPY_MODULE_FROZEN + mp_import_stat_t st = mp_frozen_stat(path); + if (st != MP_IMPORT_STAT_NO_EXIST) { + return st; + } + #endif + return mp_import_stat(path); +} + STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) { - mp_import_stat_t stat = mp_import_stat(vstr_null_terminated_str(path)); + mp_import_stat_t stat = mp_import_stat_any(vstr_null_terminated_str(path)); DEBUG_printf("stat %s: %d\n", vstr_str(path), stat); if (stat == MP_IMPORT_STAT_DIR) { return stat; } vstr_add_str(path, ".py"); - stat = mp_import_stat(vstr_null_terminated_str(path)); + stat = mp_import_stat_any(vstr_null_terminated_str(path)); if (stat == MP_IMPORT_STAT_FILE) { return stat; } #if MICROPY_PERSISTENT_CODE_LOAD vstr_ins_byte(path, path->len - 2, 'm'); - stat = mp_import_stat(vstr_null_terminated_str(path)); + stat = mp_import_stat_any(vstr_null_terminated_str(path)); if (stat == MP_IMPORT_STAT_FILE) { return stat; } @@ -182,10 +194,37 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { #endif STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { - #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER + #if MICROPY_MODULE_FROZEN || MICROPY_PERSISTENT_CODE_LOAD || MICROPY_ENABLE_COMPILER char *file_str = vstr_null_terminated_str(file); #endif + // If we support frozen modules (either as str or mpy) then try to find the + // requested filename in the list of frozen module filenames. + #if MICROPY_MODULE_FROZEN + void *modref; + int frozen_type = mp_find_frozen_module(file_str, file->len, &modref); + #endif + + // If we support frozen str modules and the compiler is enabled, and we + // found the filename in the list of frozen files, then load and execute it. + #if MICROPY_MODULE_FROZEN_STR + if (frozen_type == MP_FROZEN_STR) { + do_load_from_lexer(module_obj, modref, file_str); + return; + } + #endif + + // If we support frozen mpy modules and we found a corresponding file (and + // its data) in the list of frozen files, execute it. + #if MICROPY_MODULE_FROZEN_MPY + if (frozen_type == MP_FROZEN_MPY) { + do_execute_raw_code(module_obj, modref); + return; + } + #endif + + // If we support loading .mpy files then check if the file extension is of + // the correct format and, if so, load and execute the file. #if MICROPY_PERSISTENT_CODE_LOAD if (file_str[file->len - 3] == 'm') { mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); @@ -194,15 +233,18 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { } #endif + // If we can compile scripts then load the file and compile and execute it. #if MICROPY_ENABLE_COMPILER { mp_lexer_t *lex = mp_lexer_new_from_file(file_str); do_load_from_lexer(module_obj, lex, file_str); + return; } - #else + #endif + + // If we get here then the file was not frozen and we can't compile scripts. nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "script compilation not supported")); - #endif } STATIC void chop_component(const char *start, const char **end) { @@ -340,33 +382,6 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } DEBUG_printf("Module not yet loaded\n"); - #if MICROPY_MODULE_FROZEN - void *frozen_data; - int frozen_type = mp_find_frozen_module(mod_str, mod_len, &frozen_data); - if (frozen_type != MP_FROZEN_NONE) { - module_obj = mp_obj_new_module(module_name_qstr); - // if args[3] (fromtuple) has magic value False, set up - // this module for command-line "-m" option (set module's - // name to __main__ instead of real name). - // TODO: Duplicated below too. - if (fromtuple == mp_const_false) { - mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj); - mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); - } - #if MICROPY_MODULE_FROZEN_STR - if (frozen_type == MP_FROZEN_STR) { - do_load_from_lexer(module_obj, frozen_data, mod_str); - } - #endif - #if MICROPY_MODULE_FROZEN_MPY - if (frozen_type == MP_FROZEN_MPY) { - do_execute_raw_code(module_obj, frozen_data); - } - #endif - return module_obj; - } - #endif - uint last = 0; VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX) module_obj = MP_OBJ_NULL; @@ -445,7 +460,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false)); vstr_add_char(&path, PATH_SEP_CHAR); vstr_add_str(&path, "__init__.py"); - if (mp_import_stat(vstr_null_terminated_str(&path)) != MP_IMPORT_STAT_FILE) { + if (mp_import_stat_any(vstr_null_terminated_str(&path)) != MP_IMPORT_STAT_FILE) { vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py mp_warning("%s is imported as namespace package", vstr_str(&path)); } else { diff --git a/py/compile.c b/py/compile.c index d40d8a1ff5..df6dab063c 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2649,7 +2649,7 @@ STATIC void compile_const_object(compiler_t *comp, mp_parse_node_struct_t *pns) } typedef void (*compile_function_t)(compiler_t*, mp_parse_node_struct_t*); -STATIC compile_function_t compile_function[] = { +STATIC const compile_function_t compile_function[] = { #define nc NULL #define c(f) compile_##f #define DEF_RULE(rule, comp, kind, ...) comp, diff --git a/py/emitglue.c b/py/emitglue.c index b710371177..59bca781ef 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -382,7 +382,7 @@ mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) { // here we define mp_raw_code_load_file depending on the port // TODO abstract this away properly -#if defined(__i386__) || defined(__x86_64__) || (defined(__arm__) && (defined(__unix__))) +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || (defined(__arm__) && (defined(__unix__))) // unix file reader #include <sys/stat.h> diff --git a/py/frozenmod.c b/py/frozenmod.c index 18beb0f8e4..660167eed4 100644 --- a/py/frozenmod.c +++ b/py/frozenmod.c @@ -85,6 +85,43 @@ STATIC const mp_raw_code_t *mp_find_frozen_mpy(const char *str, size_t len) { #if MICROPY_MODULE_FROZEN +STATIC mp_import_stat_t mp_frozen_stat_helper(const char *name, const char *str) { + size_t len = strlen(str); + + for (int i = 0; *name != 0; i++) { + size_t l = strlen(name); + if (l >= len && !memcmp(str, name, len)) { + if (name[len] == 0) { + return MP_IMPORT_STAT_FILE; + } else if (name[len] == '/') { + return MP_IMPORT_STAT_DIR; + } + } + name += l + 1; + } + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_import_stat_t mp_frozen_stat(const char *str) { + mp_import_stat_t stat; + + #if MICROPY_MODULE_FROZEN_STR + stat = mp_frozen_stat_helper(mp_frozen_str_names, str); + if (stat != MP_IMPORT_STAT_NO_EXIST) { + return stat; + } + #endif + + #if MICROPY_MODULE_FROZEN_MPY + stat = mp_frozen_stat_helper(mp_frozen_mpy_names, str); + if (stat != MP_IMPORT_STAT_NO_EXIST) { + return stat; + } + #endif + + return MP_IMPORT_STAT_NO_EXIST; +} + int mp_find_frozen_module(const char *str, size_t len, void **data) { #if MICROPY_MODULE_FROZEN_STR mp_lexer_t *lex = mp_find_frozen_str(str, len); diff --git a/py/frozenmod.h b/py/frozenmod.h index a1638d2293..f08cb5e321 100644 --- a/py/frozenmod.h +++ b/py/frozenmod.h @@ -31,3 +31,4 @@ enum { }; int mp_find_frozen_module(const char *str, size_t len, void **data); +mp_import_stat_t mp_frozen_stat(const char *str); @@ -693,11 +693,8 @@ void gc_dump_alloc_table(void) { } // print header for new line of blocks // (the cast to uint32_t is for 16-bit ports) - #if EXTENSIVE_HEAP_PROFILING + //mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff)); mp_printf(&mp_plat_print, "\n%05x: ", (uint)((bl * BYTES_PER_BLOCK) & (uint32_t)0xfffff)); - #else - mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff)); - #endif } int c = ' '; switch (ATB_GET_KIND(bl)) { @@ -734,6 +731,13 @@ void gc_dump_alloc_table(void) { if (*ptr == &mp_type_tuple) { c = 'T'; } else if (*ptr == &mp_type_list) { c = 'L'; } else if (*ptr == &mp_type_dict) { c = 'D'; } + else if (*ptr == &mp_type_str || *ptr == &mp_type_bytes) { c = 'S'; } + #if MICROPY_PY_BUILTINS_BYTEARRAY + else if (*ptr == &mp_type_bytearray) { c = 'A'; } + #endif + #if MICROPY_PY_ARRAY + else if (*ptr == &mp_type_array) { c = 'A'; } + #endif #if MICROPY_PY_BUILTINS_FLOAT else if (*ptr == &mp_type_float) { c = 'F'; } #endif @@ -761,7 +765,7 @@ void gc_dump_alloc_table(void) { } break; } - case AT_TAIL: c = 't'; break; + case AT_TAIL: c = '='; break; case AT_MARK: c = 'm'; break; } mp_printf(&mp_plat_print, "%c", c); diff --git a/py/lexer.c b/py/lexer.c index 1639740d34..820f91be78 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -190,7 +190,7 @@ STATIC void indent_pop(mp_lexer_t *lex) { // c<op> = continue with <op>, if this opchar matches then continue matching // this means if the start of two ops are the same then they are equal til the last char -STATIC const char *tok_enc = +STATIC const char *const tok_enc = "()[]{},:;@~" // singles "<e=c<e=" // < <= << <<= ">e=c>e=" // > >= >> >>= @@ -227,7 +227,7 @@ STATIC const uint8_t tok_enc_kind[] = { }; // must have the same order as enum in lexer.h -STATIC const char *tok_kw[] = { +STATIC const char *const tok_kw[] = { "False", "None", "True", diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index c00ec1eb28..8a3136b1f1 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -116,7 +116,7 @@ def parse_input_headers(infiles): def make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr): qhash = compute_hash(qstr, cfg_bytes_hash) - if all(32 <= ord(c) <= 126 and c != '\\' for c in qstr): + if all(32 <= ord(c) <= 126 and c != '\\' and c != '"' for c in qstr): # qstr is all printable ASCII so render it as-is (for easier debugging) qlen = len(qstr) qdata = qstr @@ -49,7 +49,7 @@ const mp_map_t mp_const_empty_map = { // The first set of sizes are chosen so the allocation fits exactly in a // 4-word GC block, and it's not so important for these small values to be // prime. The latter sizes are prime and increase at an increasing rate. -STATIC uint16_t hash_allocation_sizes[] = { +STATIC const uint16_t hash_allocation_sizes[] = { 0, 2, 4, 6, 8, 10, 12, // +2 17, 23, 29, 37, 47, 59, 73, // *1.25 97, 127, 167, 223, 293, 389, 521, 691, 919, 1223, 1627, 2161, // *1.33 diff --git a/py/modio.c b/py/modio.c index 423315081f..2fbe6bc1e1 100644 --- a/py/modio.c +++ b/py/modio.c @@ -78,10 +78,13 @@ STATIC mp_uint_t bufwriter_write(mp_obj_t self_in, const void *buf, mp_uint_t si memcpy(self->buf + self->len, buf, rem); buf = (byte*)buf + rem; size -= rem; - mp_uint_t out_sz = mp_stream_writeall(self->stream, self->buf, self->alloc, errcode); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->alloc, errcode); + if (*errcode != 0) { return MP_STREAM_ERROR; } + // TODO: try to recover from a case of non-blocking stream, e.g. move + // remaining chunk to the beginning of buffer. + assert(out_sz == self->alloc); self->len = 0; } @@ -93,9 +96,12 @@ STATIC mp_obj_t bufwriter_flush(mp_obj_t self_in) { if (self->len != 0) { int err; - mp_uint_t out_sz = mp_stream_writeall(self->stream, self->buf, self->len, &err); + mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err); + // TODO: try to recover from a case of non-blocking stream, e.g. move + // remaining chunk to the beginning of buffer. + assert(out_sz == self->len); self->len = 0; - if (out_sz == MP_STREAM_ERROR) { + if (err != 0) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(err))); } } diff --git a/py/modmath.c b/py/modmath.c index 6abf8ab3e9..54262f6115 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -31,6 +31,11 @@ #include <math.h> +// M_PI is not part of the math.h standard and may not be defined +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + /// \module math - mathematical functions /// /// The `math` module provides some basic mathematical funtions for diff --git a/py/modstruct.c b/py/modstruct.c index cd32097388..2016add17e 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -103,29 +103,24 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { char fmt_type = get_fmt_type(&fmt); mp_uint_t size; for (size = 0; *fmt; fmt++) { - mp_uint_t align = 1; mp_uint_t cnt = 1; if (unichar_isdigit(*fmt)) { cnt = get_fmt_num(&fmt); } - mp_uint_t sz = 0; if (*fmt == 's') { - sz = cnt; - cnt = 1; - } - - while (cnt--) { - // If we already have size for 's' case, don't set it again + size += cnt; + } else { + mp_uint_t align; + size_t sz = mp_binary_get_size(fmt_type, *fmt, &align); if (sz == 0) { - sz = (mp_uint_t)mp_binary_get_size(fmt_type, *fmt, &align); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "unsupported format")); + } + while (cnt--) { + // Apply alignment + size = (size + align - 1) & ~(align - 1); + size += sz; } - // TODO - assert(sz != (mp_uint_t)-1); - // Apply alignment - size = (size + align - 1) & ~(align - 1); - size += sz; - sz = 0; } } return MP_OBJ_NEW_SMALL_INT(size); diff --git a/py/moduerrno.c b/py/moduerrno.c new file mode 100644 index 0000000000..343b29ba08 --- /dev/null +++ b/py/moduerrno.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <assert.h> +#include <string.h> + +#include "py/obj.h" +#include "py/mperrno.h" + +#if MICROPY_PY_UERRNO + +// This list could be defined per port in mpconfigport.h to tailor it to a +// specific port's needs. But for now we have a common list. +#define ERRNO_LIST \ + X(EPERM) \ + X(ENOENT) \ + X(EIO) \ + X(EBADF) \ + X(EAGAIN) \ + X(ENOMEM) \ + X(EACCES) \ + X(EEXIST) \ + X(ENODEV) \ + X(EISDIR) \ + X(EINVAL) \ + X(EOPNOTSUPP) \ + X(EADDRINUSE) \ + X(ECONNABORTED) \ + X(ECONNRESET) \ + X(ENOBUFS) \ + X(ENOTCONN) \ + X(ETIMEDOUT) \ + X(ECONNREFUSED) \ + X(EHOSTUNREACH) \ + X(EALREADY) \ + X(EINPROGRESS) \ + +STATIC const mp_rom_map_elem_t errorcode_table[] = { + #define X(e) { MP_ROM_INT(MP_ ## e), MP_ROM_QSTR(MP_QSTR_## e) }, + ERRNO_LIST + #undef X +}; + +STATIC const mp_obj_dict_t errorcode_dict = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 0, // keys are integers + .is_fixed = 1, + .is_ordered = 1, + .used = MP_ARRAY_SIZE(errorcode_table), + .alloc = MP_ARRAY_SIZE(errorcode_table), + .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)errorcode_table, + }, +}; + +STATIC const mp_rom_map_elem_t mp_module_uerrno_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uerrno) }, + { MP_ROM_QSTR(MP_QSTR_errorcode), MP_ROM_PTR(&errorcode_dict) }, + + #define X(e) { MP_ROM_QSTR(MP_QSTR_## e), MP_ROM_INT(MP_ ## e) }, + ERRNO_LIST + #undef X +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_uerrno_globals, mp_module_uerrno_globals_table); + +const mp_obj_module_t mp_module_uerrno = { + .base = { &mp_type_module }, + .name = MP_QSTR_uerrno, + .globals = (mp_obj_dict_t*)&mp_module_uerrno_globals, +}; + +qstr mp_errno_to_str(mp_obj_t errno_val) { + mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&errorcode_dict.map, errno_val, MP_MAP_LOOKUP); + if (elem == NULL) { + return MP_QSTR_NULL; + } else { + return MP_OBJ_QSTR_VALUE(elem->value); + } +} + +#endif //MICROPY_PY_UERRNO diff --git a/py/mpconfig.h b/py/mpconfig.h index 42ef19b72c..084fc246f5 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -555,6 +555,11 @@ typedef double mp_float_t; #define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1) #endif +// Whether to use internally defined errno's (otherwise system provided ones) +#ifndef MICROPY_USE_INTERNAL_ERRNO +#define MICROPY_USE_INTERNAL_ERRNO (0) +#endif + // Support for user-space VFS mount (selected ports) #ifndef MICROPY_FSUSERMOUNT #define MICROPY_FSUSERMOUNT (0) @@ -584,6 +589,11 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_STR_UNICODE (0) #endif +// Whether str.center() method provided +#ifndef MICROPY_PY_BUILTINS_STR_CENTER +#define MICROPY_PY_BUILTINS_STR_CENTER (0) +#endif + // Whether str.splitlines() method provided #ifndef MICROPY_PY_BUILTINS_STR_SPLITLINES #define MICROPY_PY_BUILTINS_STR_SPLITLINES (0) @@ -809,6 +819,11 @@ typedef double mp_float_t; #define MICROPY_PY_SYS_STDIO_BUFFER (0) #endif +// Whether to provide "uerrno" module +#ifndef MICROPY_PY_UERRNO +#define MICROPY_PY_UERRNO (0) +#endif + // Extended modules #ifndef MICROPY_PY_UCTYPES @@ -852,6 +867,11 @@ typedef double mp_float_t; #define MICROPY_PY_MACHINE (0) #endif +// Whether to include: time_pulse_us +#ifndef MICROPY_PY_MACHINE_PULSE +#define MICROPY_PY_MACHINE_PULSE (0) +#endif + #ifndef MICROPY_PY_MACHINE_I2C #define MICROPY_PY_MACHINE_I2C (0) #endif diff --git a/py/mperrno.h b/py/mperrno.h new file mode 100644 index 0000000000..4d092de452 --- /dev/null +++ b/py/mperrno.h @@ -0,0 +1,143 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_PY_MPERRNO_H__ +#define __MICROPY_INCLUDED_PY_MPERRNO_H__ + +#if MICROPY_USE_INTERNAL_ERRNO + +// MP_Exxx errno's are defined directly as numeric values +// (Linux constants are used as a reference) + +#define MP_EPERM (1) // Operation not permitted +#define MP_ENOENT (2) // No such file or directory +#define MP_ESRCH (3) // No such process +#define MP_EINTR (4) // Interrupted system call +#define MP_EIO (5) // I/O error +#define MP_ENXIO (6) // No such device or address +#define MP_E2BIG (7) // Argument list too long +#define MP_ENOEXEC (8) // Exec format error +#define MP_EBADF (9) // Bad file number +#define MP_ECHILD (10) // No child processes +#define MP_EAGAIN (11) // Try again +#define MP_ENOMEM (12) // Out of memory +#define MP_EACCES (13) // Permission denied +#define MP_EFAULT (14) // Bad address +#define MP_ENOTBLK (15) // Block device required +#define MP_EBUSY (16) // Device or resource busy +#define MP_EEXIST (17) // File exists +#define MP_EXDEV (18) // Cross-device link +#define MP_ENODEV (19) // No such device +#define MP_ENOTDIR (20) // Not a directory +#define MP_EISDIR (21) // Is a directory +#define MP_EINVAL (22) // Invalid argument +#define MP_ENFILE (23) // File table overflow +#define MP_EMFILE (24) // Too many open files +#define MP_ENOTTY (25) // Not a typewriter +#define MP_ETXTBSY (26) // Text file busy +#define MP_EFBIG (27) // File too large +#define MP_ENOSPC (28) // No space left on device +#define MP_ESPIPE (29) // Illegal seek +#define MP_EROFS (30) // Read-only file system +#define MP_EMLINK (31) // Too many links +#define MP_EPIPE (32) // Broken pipe +#define MP_EDOM (33) // Math argument out of domain of func +#define MP_ERANGE (34) // Math result not representable +#define MP_EWOULDBLOCK MP_EAGAIN // Operation would block +#define MP_EOPNOTSUPP (95) // Operation not supported on transport endpoint +#define MP_EAFNOSUPPORT (97) // Address family not supported by protocol +#define MP_EADDRINUSE (98) // Address already in use +#define MP_ECONNABORTED (103) // Software caused connection abort +#define MP_ECONNRESET (104) // Connection reset by peer +#define MP_ENOBUFS (105) // No buffer space available +#define MP_ENOTCONN (107) // Transport endpoint is not connected +#define MP_ETIMEDOUT (110) // Connection timed out +#define MP_ECONNREFUSED (111) // Connection refused +#define MP_EHOSTUNREACH (113) // No route to host +#define MP_EALREADY (114) // Operation already in progress +#define MP_EINPROGRESS (115) // Operation now in progress + +#else + +// MP_Exxx errno's are defined in terms of system supplied ones + +#include <errno.h> + +#define MP_EPERM EPERM +#define MP_ENOENT ENOENT +#define MP_ESRCH ESRCH +#define MP_EINTR EINTR +#define MP_EIO EIO +#define MP_ENXIO ENXIO +#define MP_E2BIG E2BIG +#define MP_ENOEXEC ENOEXEC +#define MP_EBADF EBADF +#define MP_ECHILD ECHILD +#define MP_EAGAIN EAGAIN +#define MP_ENOMEM ENOMEM +#define MP_EACCES EACCES +#define MP_EFAULT EFAULT +#define MP_ENOTBLK ENOTBLK +#define MP_EBUSY EBUSY +#define MP_EEXIST EEXIST +#define MP_EXDEV EXDEV +#define MP_ENODEV ENODEV +#define MP_ENOTDIR ENOTDIR +#define MP_EISDIR EISDIR +#define MP_EINVAL EINVAL +#define MP_ENFILE ENFILE +#define MP_EMFILE EMFILE +#define MP_ENOTTY ENOTTY +#define MP_ETXTBSY ETXTBSY +#define MP_EFBIG EFBIG +#define MP_ENOSPC ENOSPC +#define MP_ESPIPE ESPIPE +#define MP_EROFS EROFS +#define MP_EMLINK EMLINK +#define MP_EPIPE EPIPE +#define MP_EDOM EDOM +#define MP_ERANGE ERANGE +#define MP_EWOULDBLOCK EAGAIN +#define MP_EOPNOTSUPP EOPNOTSUPP +#define MP_EAFNOSUPPORT EAFNOSUPPORT +#define MP_EADDRINUSE EADDRINUSE +#define MP_ECONNABORTED ECONNABORTED +#define MP_ECONNRESET ECONNRESET +#define MP_ENOBUFS ENOBUFS +#define MP_ENOTCONN ENOTCONN +#define MP_ETIMEDOUT ETIMEDOUT +#define MP_ECONNREFUSED ECONNREFUSED +#define MP_EHOSTUNREACH EHOSTUNREACH +#define MP_EALREADY EALREADY +#define MP_EINPROGRESS EINPROGRESS + +#endif + +#if MICROPY_PY_UERRNO +qstr mp_errno_to_str(mp_obj_t errno_val); +#endif + +#endif // __MICROPY_INCLUDED_PY_MPERRNO_H__ diff --git a/py/mphal.h b/py/mphal.h index a0b642fc98..aacd02ebd8 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -54,8 +54,25 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len); void mp_hal_delay_ms(mp_uint_t ms); #endif +#ifndef mp_hal_delay_us +void mp_hal_delay_us(mp_uint_t us); +#endif + #ifndef mp_hal_ticks_ms mp_uint_t mp_hal_ticks_ms(void); #endif +#ifndef mp_hal_ticks_us +mp_uint_t mp_hal_ticks_us(void); +#endif + +// If port HAL didn't define its own pin API, use generic +// "virtual pin" API from the core. +#ifndef mp_hal_pin_obj_t +#define mp_hal_pin_obj_t mp_obj_t +#define mp_hal_get_pin_obj(pin) (pin) +#define mp_hal_pin_read(pin) mp_virtual_pin_read(pin) +#define mp_hal_pin_write(pin, v) mp_virtual_pin_write(pin, v) +#endif + #endif // __MICROPY_INCLUDED_PY_MPHAL_H__ @@ -454,10 +454,8 @@ STATIC mp_uint_t mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mpz_d assumes num_dig has enough memory to be extended by 1 digit assumes quo_dig has enough memory (as many digits as num) assumes quo_dig is filled with zeros - modifies den_dig memory, but restors it to original state at end */ - -STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, mp_uint_t den_len, mpz_dig_t *quo_dig, mp_uint_t *quo_len) { +STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, const mpz_dig_t *den_dig, mp_uint_t den_len, mpz_dig_t *quo_dig, mp_uint_t *quo_len) { mpz_dig_t *orig_num_dig = num_dig; mpz_dig_t *orig_quo_dig = quo_dig; mpz_dig_t norm_shift = 0; @@ -478,6 +476,11 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, } } + // We need to normalise the denominator (leading bit of leading digit is 1) + // so that the division routine works. Since the denominator memory is + // read-only we do the normalisation on the fly, each time a digit of the + // denominator is needed. We need to know is how many bits to shift by. + // count number of leading zeros in leading digit of denominator { mpz_dig_t d = den_dig[den_len - 1]; @@ -487,13 +490,6 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, } } - // normalise denomenator (leading bit of leading digit is 1) - for (mpz_dig_t *den = den_dig, carry = 0; den < den_dig + den_len; ++den) { - mpz_dig_t d = *den; - *den = ((d << norm_shift) | carry) & DIG_MASK; - carry = d >> (DIG_SIZE - norm_shift); - } - // now need to shift numerator by same amount as denominator // first, increase length of numerator in case we need more room to shift num_dig[*num_len] = 0; @@ -501,11 +497,14 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, for (mpz_dig_t *num = num_dig, carry = 0; num < num_dig + *num_len; ++num) { mpz_dig_t n = *num; *num = ((n << norm_shift) | carry) & DIG_MASK; - carry = n >> (DIG_SIZE - norm_shift); + carry = (mpz_dbl_dig_t)n >> (DIG_SIZE - norm_shift); } // cache the leading digit of the denominator - lead_den_digit = den_dig[den_len - 1]; + lead_den_digit = (mpz_dbl_dig_t)den_dig[den_len - 1] << norm_shift; + if (den_len >= 2) { + lead_den_digit |= (mpz_dbl_dig_t)den_dig[den_len - 2] >> (DIG_SIZE - norm_shift); + } // point num_dig to last digit in numerator num_dig += *num_len - 1; @@ -540,10 +539,13 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, // 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, *d = den_dig; n < num_dig; ++n, ++d) { - borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)*d; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2 + 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; } @@ -553,9 +555,12 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, // 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, *d = den_dig; n < num_dig; ++n, ++d) { - carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d; + 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; } @@ -566,10 +571,13 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, 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, *d = den_dig; n < num_dig; ++n, ++d) { - mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)(*d); + 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; @@ -590,9 +598,12 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, // 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, *d = den_dig; n < num_dig; ++n, ++d) { - carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d; + 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; } @@ -614,18 +625,11 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig, --(*num_len); } - // unnormalise denomenator - for (mpz_dig_t *den = den_dig + den_len - 1, carry = 0; den >= den_dig; --den) { - mpz_dig_t d = *den; - *den = ((d >> norm_shift) | carry) & DIG_MASK; - carry = d << (DIG_SIZE - norm_shift); - } - // unnormalise numerator (remainder now) for (mpz_dig_t *num = orig_num_dig + *num_len - 1, carry = 0; num >= orig_num_dig; --num) { mpz_dig_t n = *num; *num = ((n >> norm_shift) | carry) & DIG_MASK; - carry = n << (DIG_SIZE - norm_shift); + carry = (mpz_dbl_dig_t)n << (DIG_SIZE - norm_shift); } // strip trailing zeros @@ -1506,11 +1510,16 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m dest_quo->len = 0; mpz_need_dig(dest_rem, lhs->len + 1); // +1 necessary? mpz_set(dest_rem, lhs); - //rhs->dig[rhs->len] = 0; mpn_div(dest_rem->dig, &dest_rem->len, rhs->dig, rhs->len, dest_quo->dig, &dest_quo->len); + // check signs and do Python style modulo if (lhs->neg != rhs->neg) { dest_quo->neg = 1; + if (!mpz_is_zero(dest_rem)) { + mpz_t mpzone; mpz_init_from_int(&mpzone, -1); + mpz_add_inpl(dest_quo, dest_quo, &mpzone); + mpz_add_inpl(dest_rem, dest_rem, rhs); + } } } @@ -317,6 +317,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { #endif #endif +// note: returned value in *items may point to the interior of a GC block void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items) { if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) { mp_obj_tuple_get(o, len, items); @@ -333,6 +334,7 @@ void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items) { } } +// note: returned value in *items may point to the interior of a GC block void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items) { mp_uint_t seq_len; mp_obj_get_array(o, &seq_len, items); @@ -651,8 +651,8 @@ mp_float_t mp_obj_get_float(mp_obj_t self_in); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); #endif //qstr mp_obj_get_qstr(mp_obj_t arg); -void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items); -void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items); +void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items); // *items may point inside a GC block +void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items); // *items may point inside a GC block mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice); mp_obj_t mp_obj_id(mp_obj_t o_in); mp_obj_t mp_obj_len(mp_obj_t o_in); diff --git a/py/objdict.c b/py/objdict.c index cc1f502d0f..04da2bf624 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -414,7 +414,7 @@ typedef enum _mp_dict_view_kind_t { MP_DICT_VIEW_VALUES, } mp_dict_view_kind_t; -STATIC char *mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"}; +STATIC const char *const mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"}; typedef struct _mp_obj_dict_view_it_t { mp_obj_base_t base; diff --git a/py/objexcept.c b/py/objexcept.c index adf17b08d0..9ccc9288c9 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -36,6 +36,7 @@ #include "py/objtype.h" #include "py/runtime.h" #include "py/gc.h" +#include "py/mperrno.h" // 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}; @@ -107,6 +108,16 @@ STATIC void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_pr mp_print_str(print, ""); return; } else if (o->args->len == 1) { + #if MICROPY_PY_UERRNO + // try to provide a nice OSError error message + if (o->base.type == &mp_type_OSError && MP_OBJ_IS_SMALL_INT(o->args->items[0])) { + qstr qst = mp_errno_to_str(o->args->items[0]); + if (qst != MP_QSTR_NULL) { + mp_printf(print, "[Errno %d] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst); + return; + } + } + #endif mp_obj_print_helper(print, o->args->items[0], PRINT_STR); return; } diff --git a/py/objfloat.c b/py/objfloat.c index aa37f9ab2d..85b8b13861 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -41,6 +41,14 @@ #if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D +// M_E and M_PI are not part of the math.h standard and may not be defined +#ifndef M_E +#define M_E (2.7182818284590452354) +#endif +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + typedef struct _mp_obj_float_t { mp_obj_base_t base; mp_float_t value; diff --git a/py/objint_mpz.c b/py/objint_mpz.c index dc083827cc..3a30eb9d9b 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -239,12 +239,6 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); - if (zlhs->neg != zrhs->neg) { - if (!mpz_is_zero(&rem)) { - mpz_t mpzone; mpz_init_from_int(&mpzone, -1); - mpz_add_inpl(&res->mpz, &res->mpz, &mpzone); - } - } mpz_deinit(&rem); break; } @@ -256,10 +250,6 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mpz_t quo; mpz_init_zero(&quo); mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs); mpz_deinit(&quo); - // Check signs and do Python style modulo - if (zlhs->neg != zrhs->neg) { - mpz_add_inpl(&res->mpz, &res->mpz, zrhs); - } break; } @@ -303,10 +293,6 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } mp_obj_int_t *quo = mp_obj_int_new_mpz(); mpz_divmod_inpl(&quo->mpz, &res->mpz, zlhs, zrhs); - // Check signs and do Python style modulo - if (zlhs->neg != zrhs->neg) { - mpz_add_inpl(&res->mpz, &res->mpz, zrhs); - } mp_obj_t tuple[2] = {MP_OBJ_FROM_PTR(quo), MP_OBJ_FROM_PTR(res)}; return mp_obj_new_tuple(2, tuple); } diff --git a/py/objmodule.c b/py/objmodule.c index 8c3cb85e67..c7cb644488 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -163,6 +163,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = { // extmod modules +#if MICROPY_PY_UERRNO + { MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) }, +#endif #if MICROPY_PY_UCTYPES { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, #endif diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 76dc9a1fc9..38cda1ad75 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -165,10 +165,7 @@ STATIC mp_obj_t new_namedtuple_type(mp_obj_t name_in, mp_obj_t fields_in) { fields_in = mp_obj_str_split(1, &fields_in); } #endif - if (!MP_OBJ_IS_TYPE(fields_in, &mp_type_list)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "list required")); - } - mp_obj_list_get(fields_in, &n_fields, &fields); + mp_obj_get_array(fields_in, &n_fields, &fields); return mp_obj_new_namedtuple_type(name, n_fields, fields); } MP_DEFINE_CONST_FUN_OBJ_2(mp_namedtuple_obj, new_namedtuple_type); diff --git a/py/objstr.c b/py/objstr.c index d0d090b995..e51c371f7b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -464,9 +464,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { return mp_obj_new_str_from_vstr(self_type, &vstr); } -enum {SPLIT = 0, KEEP = 1, SPLITLINES = 2}; - -STATIC inline mp_obj_t str_split_internal(mp_uint_t n_args, const mp_obj_t *args, int type) { +mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); mp_int_t splits = -1; mp_obj_t sep = mp_const_none; @@ -527,13 +525,7 @@ STATIC inline mp_obj_t str_split_internal(mp_uint_t n_args, const mp_obj_t *args } s++; } - mp_uint_t sub_len = s - start; - if (MP_LIKELY(!(sub_len == 0 && s == top && (type && SPLITLINES)))) { - if (start + sub_len != top && (type & KEEP)) { - sub_len++; - } - mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, sub_len)); - } + mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, s - start)); if (s >= top) { break; } @@ -547,25 +539,49 @@ STATIC inline mp_obj_t str_split_internal(mp_uint_t n_args, const mp_obj_t *args return res; } -mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { - return str_split_internal(n_args, args, SPLIT); -} - #if MICROPY_PY_BUILTINS_STR_SPLITLINES STATIC mp_obj_t str_splitlines(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_keepends }; static const mp_arg_t allowed_args[] = { { MP_QSTR_keepends, MP_ARG_BOOL, {.u_bool = false} }, }; // parse args - struct { - mp_arg_val_t keepends; - } args; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, - MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_obj_type_t *self_type = mp_obj_get_type(pos_args[0]); + mp_obj_t res = mp_obj_new_list(0, NULL); + + GET_STR_DATA_LEN(pos_args[0], s, len); + const byte *top = s + len; + + while (s < top) { + const byte *start = s; + size_t match = 0; + while (s < top) { + if (*s == '\n') { + match = 1; + break; + } else if (*s == '\r') { + if (s[1] == '\n') { + match = 2; + } else { + match = 1; + } + break; + } + s++; + } + size_t sub_len = s - start; + if (args[ARG_keepends].u_bool) { + sub_len += match; + } + mp_obj_list_append(res, mp_obj_new_str_of_type(self_type, start, sub_len)); + s += match; + } - mp_obj_t new_args[2] = {pos_args[0], MP_OBJ_NEW_QSTR(MP_QSTR__0x0a_)}; - return str_split_internal(2, new_args, SPLITLINES | (args.keepends.u_bool ? KEEP : 0)); + return res; } #endif @@ -801,6 +817,23 @@ STATIC mp_obj_t str_rstrip(size_t n_args, const mp_obj_t *args) { return str_uni_strip(RSTRIP, n_args, args); } +#if MICROPY_PY_BUILTINS_STR_CENTER +STATIC mp_obj_t str_center(mp_obj_t str_in, mp_obj_t width_in) { + GET_STR_DATA_LEN(str_in, str, str_len); + mp_uint_t width = mp_obj_get_int(width_in); + if (str_len >= width) { + return str_in; + } + + vstr_t vstr; + vstr_init_len(&vstr, width); + memset(vstr.buf, ' ', width); + int left = (width - str_len) / 2; + memcpy(vstr.buf + left, str, str_len); + return mp_obj_new_str_from_vstr(mp_obj_get_type(str_in), &vstr); +} +#endif + // Takes an int arg, but only parses unsigned numbers, and only changes // *num if at least one digit was parsed. STATIC const char *str_to_int(const char *str, const char *top, int *num) { @@ -1806,7 +1839,7 @@ mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_u GET_STR_DATA_LEN(self_in, str_data, str_len); bufinfo->buf = (void*)str_data; bufinfo->len = str_len; - bufinfo->typecode = 'b'; + bufinfo->typecode = 'B'; // bytes should be unsigned, so should unicode byte-access return 0; } else { // can't write to a string @@ -1830,6 +1863,9 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, mp_obj_str_split); #if MICROPY_PY_BUILTINS_STR_SPLITLINES MP_DEFINE_CONST_FUN_OBJ_KW(str_splitlines_obj, 1, str_splitlines); #endif +#if MICROPY_PY_BUILTINS_STR_CENTER +MP_DEFINE_CONST_FUN_OBJ_2(str_center_obj, str_center); +#endif MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith); @@ -1881,6 +1917,9 @@ STATIC const mp_rom_map_elem_t str8_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, +#if MICROPY_PY_BUILTINS_STR_CENTER + { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, +#endif { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, diff --git a/py/objstr.h b/py/objstr.h index 6b8ad97ec2..07929156cb 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -92,6 +92,7 @@ MP_DECLARE_CONST_FUN_OBJ(str_replace_obj); MP_DECLARE_CONST_FUN_OBJ(str_count_obj); MP_DECLARE_CONST_FUN_OBJ(str_partition_obj); MP_DECLARE_CONST_FUN_OBJ(str_rpartition_obj); +MP_DECLARE_CONST_FUN_OBJ(str_center_obj); MP_DECLARE_CONST_FUN_OBJ(str_lower_obj); MP_DECLARE_CONST_FUN_OBJ(str_upper_obj); MP_DECLARE_CONST_FUN_OBJ(str_isspace_obj); diff --git a/py/objstringio.c b/py/objstringio.c index f50abfbc3a..5fd2ca9d3b 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -95,6 +95,7 @@ STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) { mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in); check_stringio_is_open(self); + // TODO: Try to avoid copying string return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue); diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 8099e20a0e..c6c775d109 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -238,6 +238,9 @@ STATIC const mp_rom_map_elem_t struni_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&str_count_obj) }, { MP_ROM_QSTR(MP_QSTR_partition), MP_ROM_PTR(&str_partition_obj) }, { MP_ROM_QSTR(MP_QSTR_rpartition), MP_ROM_PTR(&str_rpartition_obj) }, +#if MICROPY_PY_BUILTINS_STR_CENTER + { MP_ROM_QSTR(MP_QSTR_center), MP_ROM_PTR(&str_center_obj) }, +#endif { MP_ROM_QSTR(MP_QSTR_lower), MP_ROM_PTR(&str_lower_obj) }, { MP_ROM_QSTR(MP_QSTR_upper), MP_ROM_PTR(&str_upper_obj) }, { MP_ROM_QSTR(MP_QSTR_isspace), MP_ROM_PTR(&str_isspace_obj) }, diff --git a/py/parse.c b/py/parse.c index 3daa5ff83e..7da484c497 100644 --- a/py/parse.c +++ b/py/parse.c @@ -104,7 +104,7 @@ enum { #undef one_or_more #undef DEF_RULE -STATIC const rule_t *rules[] = { +STATIC const rule_t *const rules[] = { #define DEF_RULE(rule, comp, kind, ...) &rule_##rule, #include "py/grammar.h" #undef DEF_RULE @@ -449,6 +449,9 @@ STATIC void push_result_token(parser_t *parser) { #if MICROPY_COMP_MODULE_CONST STATIC const mp_rom_map_elem_t mp_constants_table[] = { + #if MICROPY_PY_UERRNO + { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, + #endif #if MICROPY_PY_UCTYPES { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, #endif @@ -160,6 +160,7 @@ PY_O_BASENAME = \ modmicropython.o \ modstruct.o \ modsys.o \ + moduerrno.o \ vm.o \ bc.o \ showbc.o \ @@ -173,7 +174,9 @@ PY_O_BASENAME = \ ../extmod/moduheapq.o \ ../extmod/moduhashlib.o \ ../extmod/modubinascii.o \ + ../extmod/virtpin.o \ ../extmod/machine_mem.o \ + ../extmod/machine_pulse.o \ ../extmod/machine_i2c.o \ ../extmod/modussl.o \ ../extmod/modurandom.o \ @@ -88,7 +88,7 @@ bool mp_repl_continue_with_input(const char *input) { } else if (in_quote == Q_NONE || in_quote == Q_1_DOUBLE) { in_quote = Q_1_DOUBLE - in_quote; } - } else if (*i == '\\' && (i[1] == '\'' || i[1] == '"')) { + } else if (*i == '\\' && (i[1] == '\'' || i[1] == '"' || i[1] == '\\')) { if (in_quote != Q_NONE) { i++; } @@ -126,6 +126,7 @@ bool mp_repl_continue_with_input(const char *input) { mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t *print, const char **compl_str) { // scan backwards to find start of "a.b.c" chain + const char *org_str = str; const char *top = str + len; for (const char *s = top; --s >= str;) { if (!(unichar_isalpha(*s) || unichar_isdigit(*s) || *s == '_' || *s == '.')) { @@ -219,6 +220,16 @@ mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t // nothing found if (n_found == 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) { + static const char import_str[] = "import "; + if (memcmp(s_start, import_str, s_len) == 0) { + *compl_str = import_str + s_len; + return sizeof(import_str) - 1 - s_len; + } + } + return 0; } diff --git a/py/runtime.c b/py/runtime.c index 67534c4b5e..7f28abbf4f 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -714,13 +714,18 @@ void mp_call_prepare_args_n_kw_var(bool have_self, mp_uint_t n_args_n_kw, const } } } else { - // generic mapping - // TODO is calling 'items' on the mapping the correct thing to do here? - mp_obj_t dest[2]; - mp_load_method(kw_dict, MP_QSTR_items, dest); + // generic mapping: + // - call keys() to get an iterable of all keys in the mapping + // - call __getitem__ for each key to get the corresponding value + + // get the keys iterable + mp_obj_t dest[3]; + mp_load_method(kw_dict, MP_QSTR_keys, dest); mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest)); - mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + + mp_obj_t key; + while ((key = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + // expand size of args array if needed if (args2_len + 1 >= args2_alloc) { uint new_alloc = args2_alloc * 2; if (new_alloc < 4) { @@ -729,15 +734,20 @@ void mp_call_prepare_args_n_kw_var(bool have_self, mp_uint_t n_args_n_kw, const args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc); args2_alloc = new_alloc; } - mp_obj_t *items; - mp_obj_get_array_fixed_n(item, 2, &items); + // the key must be a qstr, so intern it if it's a string - mp_obj_t key = items[0]; if (MP_OBJ_IS_TYPE(key, &mp_type_str)) { key = mp_obj_str_intern(key); } + + // get the value corresponding to the key + mp_load_method(kw_dict, MP_QSTR___getitem__, dest); + dest[2] = key; + mp_obj_t value = mp_call_method_n_kw(1, 0, dest); + + // store the key/value pair in the argument array args2[args2_len++] = key; - args2[args2_len++] = items[1]; + args2[args2_len++] = value; } } diff --git a/py/stream.c b/py/stream.c index a3df1b8fdd..ebdbe26b45 100644 --- a/py/stream.c +++ b/py/stream.c @@ -31,6 +31,7 @@ #include "py/nlr.h" #include "py/objstr.h" #include "py/stream.h" +#include "py/runtime.h" #if MICROPY_STREAMS_NON_BLOCK #include <errno.h> @@ -49,6 +50,48 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in); #define STREAM_CONTENT_TYPE(stream) (((stream)->is_text) ? &mp_type_str : &mp_type_bytes) +// Returns error condition in *errcode, if non-zero, return value is number of bytes written +// before error condition occured. If *errcode == 0, returns total bytes written (which will +// be equal to input size). +mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode, byte flags) { + byte *buf = buf_; + mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); + typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); + io_func_t io_func; + if (flags & MP_STREAM_RW_WRITE) { + io_func = (io_func_t)s->type->stream_p->write; + } else { + io_func = s->type->stream_p->read; + } + + *errcode = 0; + mp_uint_t done = 0; + while (size > 0) { + mp_uint_t out_sz = io_func(stream, buf, size, errcode); + // For read, out_sz == 0 means EOF. For write, it's unspecified + // what it means, but we don't make any progress, so returning + // is still the best option. + if (out_sz == 0) { + return done; + } + if (out_sz == MP_STREAM_ERROR) { + // If we read something before getting EAGAIN, don't leak it + if (mp_is_nonblocking_error(*errcode) && done != 0) { + *errcode = 0; + } + return done; + } + if (flags & MP_STREAM_RW_ONCE) { + return out_sz; + } + + buf += out_sz; + size -= out_sz; + done += out_sz; + } + return done; +} + const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { mp_obj_base_t *o = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); const mp_stream_p_t *stream_p = o->type->stream_p; @@ -62,7 +105,14 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { return stream_p; } -STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { +mp_obj_t mp_stream_close(mp_obj_t stream) { + // TODO: Still consider using ioctl for close + mp_obj_t dest[2]; + mp_load_method(stream, MP_QSTR_close, dest); + return mp_call_method_n_kw(0, 0, dest); +} + +STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) { const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); // What to do if sz < -1? Python docs don't specify this case. @@ -94,8 +144,8 @@ STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory")); } int error; - mp_uint_t out_sz = stream_p->read(args[0], p, more_bytes, &error); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_read_exactly(args[0], p, more_bytes, &error); + if (error != 0) { vstr_cut_tail_bytes(&vstr, more_bytes); if (mp_is_nonblocking_error(error)) { // With non-blocking streams, we read as much as we can. @@ -165,8 +215,8 @@ STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { vstr_t vstr; vstr_init_len(&vstr, sz); int error; - mp_uint_t out_sz = stream_p->read(args[0], vstr.buf, sz, &error); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_rw(args[0], vstr.buf, sz, &error, flags); + if (error != 0) { vstr_clear(&vstr); if (mp_is_nonblocking_error(error)) { // https://docs.python.org/3.4/library/io.html#io.RawIOBase.read @@ -182,20 +232,27 @@ STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { return mp_obj_new_str_from_vstr(STREAM_CONTENT_TYPE(stream_p), &vstr); } } + +STATIC mp_obj_t stream_read(size_t n_args, const mp_obj_t *args) { + return stream_read_generic(n_args, args, MP_STREAM_RW_READ); +} MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj, 1, 2, stream_read); -mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(self_in, MP_STREAM_OP_WRITE); +STATIC mp_obj_t stream_read1(size_t n_args, const mp_obj_t *args) { + return stream_read_generic(n_args, args, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj, 1, 2, stream_read1); + +mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags) { + mp_get_stream_raise(self_in, MP_STREAM_OP_WRITE); int error; - mp_uint_t out_sz = stream_p->write(self_in, buf, len, &error); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_rw(self_in, (void*)buf, len, &error, flags); + if (error != 0) { if (mp_is_nonblocking_error(error)) { // http://docs.python.org/3/library/io.html#io.RawIOBase.write // "None is returned if the raw stream is set not to block and // no single byte could be readily written to it." - // This is for consistency with read() behavior, still weird, - // see abobe. return mp_const_none; } nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error))); @@ -206,33 +263,25 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len) { // XXX hack void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { - mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len); -} - -// Works only with blocking streams -mp_uint_t mp_stream_writeall(mp_obj_t stream, const byte *buf, mp_uint_t size, int *errcode) { - mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream); - mp_uint_t org_size = size; - while (size > 0) { - mp_uint_t out_sz = s->type->stream_p->write(stream, buf, size, errcode); - if (out_sz == MP_STREAM_ERROR) { - return MP_STREAM_ERROR; - } - buf += out_sz; - size -= out_sz; - } - return org_size; + mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE); } STATIC mp_obj_t stream_write_method(mp_obj_t self_in, mp_obj_t arg) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - return mp_stream_write(self_in, bufinfo.buf, bufinfo.len); + return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE); } MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write_obj, stream_write_method); +STATIC mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); + return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE | MP_STREAM_RW_ONCE); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method); + STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { - const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); @@ -248,8 +297,8 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { } int error; - mp_uint_t out_sz = stream_p->read(args[0], bufinfo.buf, len, &error); - if (out_sz == MP_STREAM_ERROR) { + mp_uint_t out_sz = mp_stream_read_exactly(args[0], bufinfo.buf, len, &error); + if (error != 0) { if (mp_is_nonblocking_error(error)) { return mp_const_none; } diff --git a/py/stream.h b/py/stream.h index df6e94adfd..b0f45e2f02 100644 --- a/py/stream.h +++ b/py/stream.h @@ -48,11 +48,13 @@ struct mp_stream_seek_t { }; MP_DECLARE_CONST_FUN_OBJ(mp_stream_read_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_stream_read1_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_readinto_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_readall_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readline_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readlines_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_write_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_stream_write1_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_seek_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_tell_obj); MP_DECLARE_CONST_FUN_OBJ(mp_stream_ioctl_obj); @@ -63,14 +65,20 @@ MP_DECLARE_CONST_FUN_OBJ(mp_stream_ioctl_obj); #define MP_STREAM_OP_IOCTL (4) const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags); +mp_obj_t mp_stream_close(mp_obj_t stream); // Iterator which uses mp_stream_unbuffered_readline_obj mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self); -mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len); +mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags); -// Helper function to write entire buf to *blocking* stream -mp_uint_t mp_stream_writeall(mp_obj_t stream, const byte *buf, mp_uint_t size, int *errcode); +// C-level helper functions +#define MP_STREAM_RW_READ 0 +#define MP_STREAM_RW_WRITE 2 +#define MP_STREAM_RW_ONCE 1 +mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf, mp_uint_t size, int *errcode, byte flags); +#define mp_stream_write_exactly(stream, buf, size, err) mp_stream_rw(stream, (byte*)buf, size, err, MP_STREAM_RW_WRITE) +#define mp_stream_read_exactly(stream, buf, size, err) mp_stream_rw(stream, buf, size, err, MP_STREAM_RW_READ) #if MICROPY_STREAMS_NON_BLOCK // TODO: This is POSIX-specific (but then POSIX is the only real thing, diff --git a/py/vmentrytable.h b/py/vmentrytable.h index f3143b5d1d..9df1e40a32 100644 --- a/py/vmentrytable.h +++ b/py/vmentrytable.h @@ -29,7 +29,7 @@ #pragma clang diagnostic ignored "-Winitializer-overrides" #endif // __clang__ -static void* entry_table[256] = { +static const void *const entry_table[256] = { [0 ... 255] = &&entry_default, [MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE, [MP_BC_LOAD_CONST_NONE] = &&entry_MP_BC_LOAD_CONST_NONE, @@ -151,7 +151,7 @@ STATIC bool vstr_ensure_extra(vstr_t *vstr, size_t size) { if (vstr->fixed_buf) { return false; } - size_t new_alloc = ROUND_ALLOC((vstr->len + size) + 64); + size_t new_alloc = ROUND_ALLOC((vstr->len + size) + 16); char *new_buf = m_renew(char, vstr->buf, vstr->alloc, new_alloc); if (new_buf == NULL) { vstr->had_error = true; @@ -181,9 +181,15 @@ char *vstr_add_len(vstr_t *vstr, size_t len) { // Doesn't increase len, just makes sure there is a null byte at the end char *vstr_null_terminated_str(vstr_t *vstr) { - if (vstr->had_error || !vstr_ensure_extra(vstr, 1)) { + if (vstr->had_error) { return NULL; } + // If there's no more room, add single byte + if (vstr->alloc == vstr->len) { + if (vstr_extend(vstr, 1) == NULL) { + return NULL; + } + } vstr->buf[vstr->len] = '\0'; return vstr->buf; } diff --git a/stmhal/Makefile b/stmhal/Makefile index fffedd326c..1ad2783fca 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -284,24 +284,22 @@ endif ifneq ($(FROZEN_MPY_DIR),) # To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). -FROZEN_MPY_PY_FILES := $(wildcard $(FROZEN_MPY_DIR)/*.py) +FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY -OBJ += $(BUILD)/$(FROZEN_MPY_DIR)/frozen_mpy.o +OBJ += $(BUILD)/$(BUILD)/frozen_mpy.o MPY_CROSS = ../mpy-cross/mpy-cross MPY_TOOL = ../tools/mpy-tool.py $(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py @$(ECHO) "MPY $<" - $(Q)$(MPY_CROSS) -o $@ $^ + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ -$(BUILD)/$(FROZEN_MPY_DIR)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h +$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h @$(ECHO) "Creating $@" $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ - -$(BUILD)/$(FROZEN_MPY_DIR)/frozen_mpy.o: $(BUILD)/$(FROZEN_MPY_DIR)/frozen_mpy.c - $(call compile_c) endif .PHONY: deploy diff --git a/stmhal/boards/LIMIFROG/board_init.c b/stmhal/boards/LIMIFROG/board_init.c new file mode 100644 index 0000000000..72f9208424 --- /dev/null +++ b/stmhal/boards/LIMIFROG/board_init.c @@ -0,0 +1,154 @@ +// The code is this file allows the user to enter DFU mode when the board +// starts up, by connecting POS10 on the external connector to GND. +// The code itself is taken from the LimiFrog software repository found at +// https://github.com/LimiFrog/LimiFrog-SW, and the original license header +// is copied below. + +#include STM32_HAL_H + +static void LBF_DFU_If_Needed(void); + +void LIMIFROG_board_early_init(void) { + LBF_DFU_If_Needed(); +} + +/******************************************************************************* + * LBF_DFU_If_Needed.c + * + * (c)2015 LimiFrog / CYMEYA + * This program is licensed under the terms of the MIT License. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. + * Please refer to the License File LICENSE.txt located at the root of this + * project for full licensing conditions, + * or visit https://opensource.org/licenses/MIT. + ******************************************************************************/ + +#define __LIMIFROG_02 + +/* ==== BTLE (excl UART) ======================================== */ +// PC9 = BT_RST (active high) + +#define BT_RST_PIN GPIO_PIN_9 +#define BT_RST_PORT GPIOC + +// Position 10 +#ifdef __LIMIFROG_01 + #define CONN_POS10_PIN GPIO_PIN_9 + #define CONN_POS10_PORT GPIOB +#else + #define CONN_POS10_PIN GPIO_PIN_8 + #define CONN_POS10_PORT GPIOB +#endif + +static inline void GPIO_HIGH(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + GPIOx->BSRR = (uint32_t)GPIO_Pin; +} + +static inline int IS_GPIO_RESET(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + GPIO_PinState bitstatus; + if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET) + { + bitstatus = GPIO_PIN_SET; + } + else + { + bitstatus = GPIO_PIN_RESET; + } + return (bitstatus==GPIO_PIN_RESET); +} + +/************************************************************** + RATIONALE FOR THIS FUNCTION : + + - The STM32 embeds in ROM a bootloader that allows to + obtain code and boot from a number of different interfaces, + including USB in a mode called "DFU" (Device Frimware Update) + [see AN3606 from ST for full details] + This bootloader code is executed instead of the regular + application code when pin BOOT0 is pulled-up (which on + LimiFrog0.2 is achieved by pressing the general-purpose + pushbutton switch on the side. + - The bootloader monitors a number of IOs of the STM32 to decide + from which interface it should boot. + - Problem in LimiFrog (up to versions 0.2a at least): upon + power-up the BLE modules generates some activity on UART3, + which is part of the pins monitored by the STM32. + This misleads the bootloader in trying to boot from UART3 + and, as a result, not continuing with booting from USB. + + - This code implements an alternative solution to launch the + bootloader while making sure UART3 remains stable. + - The idea it to start application code with a check, prior to any + other applicative code, of whether USB bootload is required (as + flagged by a GPIO pulled low at reset, in the same way as BOOT0). + The hadware reset pin of BLE is asserted (so that now it won't + generate any acitivity on UART3), and if USB bootload is required : + bootload ROM is remapped at address 0x0, stack pointer is + updated and the code is branched to the start of the bootloader. + - This code is run prior to any applicative configuration of clocks, + IRQs etc. -- the STM32 is therefore still running from MSI + + THIS FUNCTION MAY BE SUPPRESSED IF YOU NEVER NEED TO BOOT DFU MODE + + ********************************************************************/ + +static void LBF_DFU_If_Needed(void) +{ + + + GPIO_InitTypeDef GPIO_InitStruct; + + + // Initialize and assert pin BTLE_RST + // (hw reset to BLE module, so it won't drive UART3) + + __GPIOC_CLK_ENABLE(); + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + GPIO_InitStruct.Pin = BT_RST_PIN; + HAL_GPIO_Init(BT_RST_PORT, &GPIO_InitStruct); + + GPIO_HIGH(BT_RST_PORT, BT_RST_PIN); // assert BTLE reset + + + /* -- Bootloader will be called if position 10 on the extension port + is actively pulled low -- */ + // Note - this is an arbitrary choice, code could be modified to + // monitor another GPIO of the STM32 and/or decide that active level + // is high rather than low + + + // Initialize Extension Port Position 10 = PB8 (bears I2C1_SCL) + // Use weak pull-up to detect if pin is externally pulled low + + __GPIOB_CLK_ENABLE(); + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Pin = CONN_POS10_PIN; + HAL_GPIO_Init(CONN_POS10_PORT, &GPIO_InitStruct); + + // If selection pin pulled low... + if ( IS_GPIO_RESET(CONN_POS10_PORT, CONN_POS10_PIN )) + + { + // Remap bootloader ROM (ie System Flash) to address 0x0 + SYSCFG->MEMRMP = 0x00000001; + + // Init stack pointer with value residing at ROM base + asm ( + "LDR R0, =0x00000000\n\t" // load ROM base address" + "LDR SP,[R0, #0]\n\t" // assign main stack pointer" + ); + + // Jump to address pointed by 0x00000004 -- */ + + asm ( + "LDR R0,[R0, #4]\n\t" // load bootloader address + "BX R0\n\t" + ); + + } +} diff --git a/stmhal/boards/LIMIFROG/mpconfigboard.h b/stmhal/boards/LIMIFROG/mpconfigboard.h new file mode 100644 index 0000000000..782c9c90f8 --- /dev/null +++ b/stmhal/boards/LIMIFROG/mpconfigboard.h @@ -0,0 +1,71 @@ +#include STM32_HAL_H + +#define MICROPY_HW_BOARD_NAME "LIMIFROG" +#define MICROPY_HW_MCU_NAME "STM32L476" + +#define MICROPY_HW_HAS_SWITCH (1) +#define MICROPY_HW_HAS_FLASH (1) +#define MICROPY_HW_HAS_SDCARD (0) +#define MICROPY_HW_HAS_MMA7660 (0) +#define MICROPY_HW_HAS_LIS3DSH (0) +#define MICROPY_HW_HAS_LCD (0) +#define MICROPY_HW_ENABLE_RNG (1) +#define MICROPY_HW_ENABLE_RTC (1) +#define MICROPY_HW_ENABLE_TIMER (1) +#define MICROPY_HW_ENABLE_SERVO (0) +#define MICROPY_HW_ENABLE_DAC (0) +#define MICROPY_HW_ENABLE_CAN (0) + +#define MICROPY_BOARD_EARLY_INIT LIMIFROG_board_early_init +void LIMIFROG_board_early_init(void); + +// MSI is used and is 4MHz +#define MICROPY_HW_CLK_PLLM (1) +#define MICROPY_HW_CLK_PLLN (40) +#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) +#define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) + +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 + +// USART config +#define MICROPY_HW_UART3_PORT (GPIOC) +#define MICROPY_HW_UART3_PINS (GPIO_PIN_10 | GPIO_PIN_11) + +// I2C busses +#define MICROPY_HW_I2C1_SCL (pin_B8) +#define MICROPY_HW_I2C1_SDA (pin_B9) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) +// We use an array of baudrates and corresponding TIMINGR values. +// +// 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 + +// SPI busses +#define MICROPY_HW_SPI1_NSS (pin_A4) +#define MICROPY_HW_SPI1_SCK (pin_A5) +#define MICROPY_HW_SPI1_MISO (pin_A6) +#define MICROPY_HW_SPI1_MOSI (pin_A7) + +#define MICROPY_HW_SPI3_NSS (pin_A15) +#define MICROPY_HW_SPI3_SCK (pin_B3) +#define MICROPY_HW_SPI3_MISO (pin_B4) +#define MICROPY_HW_SPI3_MOSI (pin_B5) + +#define MICROPY_HW_USRSW_PIN (pin_A15) +#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_C3) // red +#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) +#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRR = pin->pin_mask) +#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRR = pin->pin_mask<<16) + +// USB config +// #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/stmhal/boards/LIMIFROG/mpconfigboard.mk b/stmhal/boards/LIMIFROG/mpconfigboard.mk new file mode 100644 index 0000000000..cb89e25f5b --- /dev/null +++ b/stmhal/boards/LIMIFROG/mpconfigboard.mk @@ -0,0 +1,4 @@ +MCU_SERIES = l4 +CMSIS_MCU = STM32L476xx +AF_FILE = boards/stm32l476_af.csv +LD_FILE = boards/stm32l476xe.ld diff --git a/stmhal/boards/LIMIFROG/pins.csv b/stmhal/boards/LIMIFROG/pins.csv new file mode 100644 index 0000000000..52f96b669c --- /dev/null +++ b/stmhal/boards/LIMIFROG/pins.csv @@ -0,0 +1,114 @@ +PA0,PA0 +PA1,PA1 +PA2,PA2 +PA3,PA3 +PA4,PA4 +PA5,PA5 +PA6,PA6 +PA7,PA7 +PA8,PA8 +PA9,PA9 +PA10,PA10 +PA11,PA11 +PA12,PA12 +PA13,PA13 +PA14,PA14 +PA15,PA15 +PB0,PB0 +PB1,PB1 +PB2,PB2 +PB3,PB3 +PB4,PB4 +PB5,PB5 +PB6,PB6 +PB7,PB7 +PB8,PB8 +PB9,PB9 +PB10,PB10 +PB11,PB11 +PB12,PB12 +PB13,PB13 +PB14,PB14 +PB15,PB15 +PC0,PC0 +PC1,PC1 +PC2,PC2 +PC3,PC3 +PC4,PC4 +PC5,PC5 +PC6,PC6 +PC7,PC7 +PC8,PC8 +PC9,PC9 +PC10,PC10 +PC11,PC11 +PC12,PC12 +PC13,PC13 +PC14,PC14 +PC15,PC15 +PD0,PD0 +PD1,PD1 +PD2,PD2 +PD3,PD3 +PD4,PD4 +PD5,PD5 +PD6,PD6 +PD7,PD7 +PD8,PD8 +PD9,PD9 +PD10,PD10 +PD11,PD11 +PD12,PD12 +PD13,PD13 +PD14,PD14 +PD15,PD15 +PE0,PE0 +PE1,PE1 +PE2,PE2 +PE3,PE3 +PE4,PE4 +PE5,PE5 +PE6,PE6 +PE7,PE7 +PE8,PE8 +PE9,PE9 +PE10,PE10 +PE11,PE11 +PE12,PE12 +PE13,PE13 +PE14,PE14 +PE15,PE15 +PF0,PF0 +PF1,PF1 +PF2,PF2 +PF3,PF3 +PF4,PF4 +PF5,PF5 +PF6,PF6 +PF7,PF7 +PF8,PF8 +PF9,PF9 +PF10,PF10 +PF11,PF11 +PF12,PF12 +PF13,PF13 +PF14,PF14 +PF15,PF15 +PG0,PG0 +PG1,PG1 +PG2,PG2 +PG3,PG3 +PG4,PG4 +PG5,PG5 +PG6,PG6 +PG7,PG7 +PG8,PG8 +PG9,PG9 +PG10,PG10 +PG11,PG11 +PG12,PG12 +PG13,PG13 +PG14,PG14 +PG15,PG15 +PH0,PH0 +PH1,PH1 diff --git a/stmhal/boards/LIMIFROG/stm32l4xx_hal_conf.h b/stmhal/boards/LIMIFROG/stm32l4xx_hal_conf.h new file mode 100644 index 0000000000..9348e06790 --- /dev/null +++ b/stmhal/boards/LIMIFROG/stm32l4xx_hal_conf.h @@ -0,0 +1,373 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_conf.h + * @author MCD Application Team + * @version V1.2.0 + * @date 25-November-2015 + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32l4xx_hal_conf.h. + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_HAL_CONF_H +#define __STM32L4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +#define USE_USB_FS +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CAN_MODULE_ENABLED +/* #define HAL_COMP_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +#define HAL_DAC_MODULE_ENABLED +/* #define HAL_DFSDM_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +/* #define HAL_FIREWALL_MODULE_ENABLED */ +#define HAL_FLASH_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LCD_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_OPAMP_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_RCC_MODULE_ENABLED +#define HAL_RNG_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_SMBUS_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/* #define HAL_SWPMI_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/* #define HAL_TSC_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ + + +/* ########################## Oscillator Values adaptation ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined (MSI_VALUE) + #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000) /*!< Time out for LSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI1_CLOCK_VALUE) + #define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/** + * @brief External clock source for SAI2 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source + * frequency. + */ +#if !defined (EXTERNAL_SAI2_CLOCK_VALUE) + #define EXTERNAL_SAI2_CLOCK_VALUE ((uint32_t)48000) /*!< Value of the SAI2 External clock source in Hz*/ +#endif /* EXTERNAL_SAI2_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0x00) /*!< tick interrupt priority */ +#define USE_RTOS 0 +#define PREFETCH_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define DATA_CACHE_ENABLE 1 + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1 */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32l4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32l4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32l4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32l4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32l4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32l4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32l4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32l4xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32l4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32l4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32l4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FIREWALL_MODULE_ENABLED + #include "stm32l4xx_hal_firewall.h" +#endif /* HAL_FIREWALL_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32l4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32l4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32l4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32l4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32l4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32l4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LCD_MODULE_ENABLED + #include "stm32l4xx_hal_lcd.h" +#endif /* HAL_LCD_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32l4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32l4xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32l4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32l4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32l4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32l4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32l4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32l4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32l4xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32l4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_SWPMI_MODULE_ENABLED + #include "stm32l4xx_hal_swpmi.h" +#endif /* HAL_SWPMI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32l4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED + #include "stm32l4xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32l4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32l4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32l4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32l4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32l4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32l4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32l4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/stmhal/boards/PYBLITEV10/mpconfigboard.h b/stmhal/boards/PYBLITEV10/mpconfigboard.h index 97c972095a..83dcb938b3 100644 --- a/stmhal/boards/PYBLITEV10/mpconfigboard.h +++ b/stmhal/boards/PYBLITEV10/mpconfigboard.h @@ -71,8 +71,8 @@ #define MICROPY_HW_LED2 (pin_A14) // green #define MICROPY_HW_LED3 (pin_A15) // yellow #define MICROPY_HW_LED4 (pin_B4) // blue -#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 } -#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } #define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) #define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) #define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h index bc1d848b77..c654ec9a70 100644 --- a/stmhal/boards/PYBV10/mpconfigboard.h +++ b/stmhal/boards/PYBV10/mpconfigboard.h @@ -82,8 +82,8 @@ #define MICROPY_HW_LED2 (pin_A14) // green #define MICROPY_HW_LED3 (pin_A15) // yellow #define MICROPY_HW_LED4 (pin_B4) // blue -#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 } -#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } #define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) #define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) #define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) diff --git a/stmhal/boards/PYBV11/mpconfigboard.h b/stmhal/boards/PYBV11/mpconfigboard.h index b3c0983e34..9b5b7de27b 100644 --- a/stmhal/boards/PYBV11/mpconfigboard.h +++ b/stmhal/boards/PYBV11/mpconfigboard.h @@ -82,8 +82,8 @@ #define MICROPY_HW_LED2 (pin_A14) // green #define MICROPY_HW_LED3 (pin_A15) // yellow #define MICROPY_HW_LED4 (pin_B4) // blue -#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 } -#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } #define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) #define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) #define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) diff --git a/stmhal/boards/PYBV3/mpconfigboard.h b/stmhal/boards/PYBV3/mpconfigboard.h index 67877fd0b2..44fb221610 100644 --- a/stmhal/boards/PYBV3/mpconfigboard.h +++ b/stmhal/boards/PYBV3/mpconfigboard.h @@ -66,10 +66,13 @@ #define MICROPY_HW_USRSW_PRESSED (0) // LEDs +#define MICROPY_HW_LED_INVERTED (1) // LEDs are on when pin is driven low #define MICROPY_HW_LED1 (pin_A8) // R1 - red #define MICROPY_HW_LED2 (pin_A10) // R2 - red #define MICROPY_HW_LED3 (pin_C4) // G1 - green #define MICROPY_HW_LED4 (pin_C5) // G2 - green +#define MICROPY_HW_LED1_PWM { TIM1, 1, TIM_CHANNEL_1, GPIO_AF1_TIM1 } +#define MICROPY_HW_LED2_PWM { TIM1, 1, TIM_CHANNEL_3, GPIO_AF1_TIM1 } #define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) #define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRH = pin->pin_mask) #define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRL = pin->pin_mask) diff --git a/stmhal/boards/PYBV4/mpconfigboard.h b/stmhal/boards/PYBV4/mpconfigboard.h index 7c75508ed4..cc931fb6bf 100644 --- a/stmhal/boards/PYBV4/mpconfigboard.h +++ b/stmhal/boards/PYBV4/mpconfigboard.h @@ -79,8 +79,8 @@ #define MICROPY_HW_LED2 (pin_A14) // green #define MICROPY_HW_LED3 (pin_A15) // yellow #define MICROPY_HW_LED4 (pin_B4) // blue -#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 } -#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 } +#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } +#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } #define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) #define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) #define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) diff --git a/stmhal/boards/STM32L476DISC/mpconfigboard.h b/stmhal/boards/STM32L476DISC/mpconfigboard.h index f4617e67df..79857ccc26 100644 --- a/stmhal/boards/STM32L476DISC/mpconfigboard.h +++ b/stmhal/boards/STM32L476DISC/mpconfigboard.h @@ -16,11 +16,11 @@ #define MICROPY_HW_ENABLE_DAC (0) #define MICROPY_HW_ENABLE_CAN (0) -// HSE is 8MHz -#define MICROPY_HW_CLK_PLLM (2) +// MSI is used and is 4MHz +#define MICROPY_HW_CLK_PLLM (1) #define MICROPY_HW_CLK_PLLN (40) #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV7) -#define MICROPY_HW_CLK_PLLR (RCC_PLLP_DIV7) +#define MICROPY_HW_CLK_PLLR (RCC_PLLR_DIV2) #define MICROPY_HW_CLK_PLLQ (RCC_PLLQ_DIV2) #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_4 @@ -32,6 +32,8 @@ // I2C busses #define MICROPY_HW_I2C1_SCL (pin_B6) #define MICROPY_HW_I2C1_SDA (pin_B7) +#define MICROPY_HW_I2C2_SCL (pin_B10) +#define MICROPY_HW_I2C2_SDA (pin_B11) // We use an array of baudrates and corresponding TIMINGR values. // // The value 0x90112626 was obtained from the DISCOVERY_I2C1_TIMING constant diff --git a/stmhal/boards/stm32l476xe.ld b/stmhal/boards/stm32l476xe.ld new file mode 100644 index 0000000000..a4b1ce0974 --- /dev/null +++ b/stmhal/boards/stm32l476xe.ld @@ -0,0 +1,134 @@ +/* + GNU linker script for STM32L476XE +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K + FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x0000800 /* sector 0, 2 KiB */ + FLASH_FS (r) : ORIGIN = 0x08000800, LENGTH = 0x001F800 /* sectors 1-63 (2K each = 126 KiB) */ + FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x0060000 /* Sector starting @ 64 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K + SRAM2 (xrw) : ORIGIN = 0x10000000, LENGTH = 32K +} + +ENTRY(Reset_Handler) + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* Define the top end of the stack. The stack is full descending so begins just + above last byte of RAM. Note that EABI requires the stack to be 8-byte + aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +/* RAM extents for the garbage collector */ +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_end = 0x20014000; /* tunable */ + + +/* define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + + . = ALIGN(4); + } >FLASH_ISR + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.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_TEXT + + /* + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } >FLASH + + .ARM : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + */ + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + 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 */ + _ram_start = .; /* create a global symbol at ram start for garbage collector */ + *(.data) /* .data sections */ + *(.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_TEXT + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss) + *(.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); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + _heap_start = .; /* define a global symbol at heap start */ + . = . + _minimum_heap_size; + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + /* Remove information from the standard libraries */ + /* + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + */ + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/stmhal/can.c b/stmhal/can.c index b2330cd9c1..262c487f62 100644 --- a/stmhal/can.c +++ b/stmhal/can.c @@ -27,12 +27,12 @@ #include <stdio.h> #include <string.h> #include <stdarg.h> -#include <errno.h> #include "py/nlr.h" #include "py/objtuple.h" #include "py/runtime.h" #include "py/gc.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "bufhelper.h" #include "can.h" @@ -343,44 +343,61 @@ STATIC mp_obj_t pyb_can_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp // check arguments mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); - // create object - pyb_can_obj_t *o = m_new_obj(pyb_can_obj_t); - o->base.type = &pyb_can_type; - o->is_enabled = false; - // work out port - o->can_id = 0; + mp_uint_t can_idx; if (MP_OBJ_IS_STR(args[0])) { const char *port = mp_obj_str_get_str(args[0]); if (0) { #ifdef MICROPY_HW_CAN1_NAME } else if (strcmp(port, MICROPY_HW_CAN1_NAME) == 0) { - o->can_id = PYB_CAN_1; + can_idx = PYB_CAN_1; #endif #ifdef MICROPY_HW_CAN2_NAME } else if (strcmp(port, MICROPY_HW_CAN2_NAME) == 0) { - o->can_id = PYB_CAN_2; + can_idx = PYB_CAN_2; #endif } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN port %s does not exist", port)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN(%s) does not exist", port)); } } else { - o->can_id = mp_obj_get_int(args[0]); + can_idx = mp_obj_get_int(args[0]); + } + if (can_idx < 1 || can_idx > MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all))) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "CAN(%d) does not exist", can_idx)); + } + + pyb_can_obj_t *self; + if (MP_STATE_PORT(pyb_can_obj_all)[can_idx - 1] == NULL) { + self = m_new_obj(pyb_can_obj_t); + self->base.type = &pyb_can_type; + self->can_id = can_idx; + self->is_enabled = false; + MP_STATE_PORT(pyb_can_obj_all)[can_idx - 1] = self; + } else { + self = MP_STATE_PORT(pyb_can_obj_all)[can_idx - 1]; } - o->rxcallback0 = mp_const_none; - o->rxcallback1 = mp_const_none; - MP_STATE_PORT(pyb_can_obj_all)[o->can_id - 1] = o; - o->rx_state0 = RX_STATE_FIFO_EMPTY; - o->rx_state1 = RX_STATE_FIFO_EMPTY; - if (n_args > 1 || n_kw > 0) { - // start the peripheral - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - pyb_can_init_helper(o, n_args - 1, args + 1, &kw_args); + if (!self->is_enabled || n_args > 1) { + if (self->is_enabled) { + // The caller is requesting a reconfiguration of the hardware + // this can only be done if the hardware is in init mode + pyb_can_deinit(self); + } + + self->rxcallback0 = mp_const_none; + self->rxcallback1 = mp_const_none; + self->rx_state0 = RX_STATE_FIFO_EMPTY; + self->rx_state1 = RX_STATE_FIFO_EMPTY; + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_can_init_helper(self, n_args - 1, args + 1, &kw_args); + } } - return o; + return self; } STATIC mp_obj_t pyb_can_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { @@ -800,7 +817,7 @@ mp_uint_t can_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *err ret |= MP_IOCTL_POLL_WR; } } else { - *errcode = EINVAL; + *errcode = MP_EINVAL; ret = -1; } return ret; diff --git a/stmhal/dac.c b/stmhal/dac.c index 6d7491c314..7493bb59ab 100644 --- a/stmhal/dac.c +++ b/stmhal/dac.c @@ -67,7 +67,7 @@ /// dac = DAC(1) /// dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR) -#if MICROPY_HW_ENABLE_DAC +#if defined(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC STATIC DAC_HandleTypeDef DAC_Handle; @@ -139,7 +139,7 @@ typedef enum { typedef struct _pyb_dac_obj_t { mp_obj_base_t base; uint32_t dac_channel; // DAC_CHANNEL_1 or DAC_CHANNEL_2 - DMA_Stream_TypeDef *dma_stream; // DMA1_Stream5 or DMA1_Stream6 + const dma_descr_t *tx_dma_descr; uint16_t pin; // GPIO_PIN_4 or GPIO_PIN_5 uint8_t bits; // 8 or 12 uint8_t state; @@ -162,7 +162,13 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, mp_uint_t n_args, const HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // DAC peripheral clock + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) __DAC_CLK_ENABLE(); + #elif defined(MCU_SERIES_L4) + __HAL_RCC_DAC1_CLK_ENABLE(); + #else + #error Unsupported Processor + #endif // stop anything already going on HAL_DAC_Stop(&DAC_Handle, self->dac_channel); @@ -217,11 +223,11 @@ STATIC mp_obj_t pyb_dac_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp if (dac_id == 1) { dac->pin = GPIO_PIN_4; dac->dac_channel = DAC_CHANNEL_1; - dac->dma_stream = DMA_STREAM_DAC1; + dac->tx_dma_descr = &dma_DAC_1_TX; } else if (dac_id == 2) { dac->pin = GPIO_PIN_5; dac->dac_channel = DAC_CHANNEL_2; - dac->dma_stream = DMA_STREAM_DAC2; + dac->tx_dma_descr = &dma_DAC_2_TX; } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "DAC %d does not exist", dac_id)); } @@ -240,6 +246,21 @@ STATIC mp_obj_t pyb_dac_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *k } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_init_obj, 1, pyb_dac_init); +/// \method deinit() +/// Turn off the DAC, enable other use of pin. +STATIC mp_obj_t pyb_dac_deinit(mp_obj_t self_in) { + pyb_dac_obj_t *self = self_in; + if (self->dac_channel == DAC_CHANNEL_1) { + DAC_Handle.Instance->CR &= ~DAC_CR_EN1; + DAC_Handle.Instance->CR |= DAC_CR_BOFF1; + } else { + DAC_Handle.Instance->CR &= ~DAC_CR_EN2; + DAC_Handle.Instance->CR |= DAC_CR_BOFF2; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_dac_deinit_obj, pyb_dac_deinit); + #if defined(TIM6) /// \method noise(freq) /// Generate a pseudo-random noise signal. A new random sample is written @@ -371,9 +392,12 @@ mp_obj_t pyb_dac_write_timed(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ __DMA1_CLK_ENABLE(); + DMA_HandleTypeDef DMA_Handle; + /* Get currently configured dma */ + dma_init_handle(&DMA_Handle, self->tx_dma_descr, (void*)NULL); /* - DMA_Cmd(self->dma_stream, DISABLE); - while (DMA_GetCmdStatus(self->dma_stream) != DISABLE) { + DMA_Cmd(DMA_Handle->Instance, DISABLE); + while (DMA_GetCmdStatus(DMA_Handle->Instance) != DISABLE) { } DAC_Cmd(self->dac_channel, DISABLE); @@ -389,18 +413,10 @@ mp_obj_t pyb_dac_write_timed(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ DAC_Init(self->dac_channel, &DAC_InitStructure); */ - // DMA1_Stream[67] channel7 configuration - DMA_HandleTypeDef DMA_Handle; - DMA_Handle.Instance = self->dma_stream; - // Need to deinit DMA first DMA_Handle.State = HAL_DMA_STATE_READY; HAL_DMA_DeInit(&DMA_Handle); - DMA_Handle.Init.Channel = DMA_CHANNEL_DAC1; // DAC1 & DAC2 both use the same channel - DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH; - DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE; - DMA_Handle.Init.MemInc = DMA_MINC_ENABLE; if (self->bits == 8) { DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; @@ -409,11 +425,6 @@ mp_obj_t pyb_dac_write_timed(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; } DMA_Handle.Init.Mode = args[2].u_int; - DMA_Handle.Init.Priority = DMA_PRIORITY_HIGH; - DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; - DMA_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL; - DMA_Handle.Init.MemBurst = DMA_MBURST_SINGLE; - DMA_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE; HAL_DMA_Init(&DMA_Handle); if (self->dac_channel == DAC_CHANNEL_1) { @@ -444,8 +455,8 @@ mp_obj_t pyb_dac_write_timed(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ /* // enable DMA stream - DMA_Cmd(self->dma_stream, ENABLE); - while (DMA_GetCmdStatus(self->dma_stream) == DISABLE) { + DMA_Cmd(DMA_Handle->Instance, ENABLE); + while (DMA_GetCmdStatus(DMA_Handle->Instance) == DISABLE) { } // enable DAC channel @@ -465,6 +476,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_write_timed_obj, 1, pyb_dac_write_time STATIC const mp_map_elem_t pyb_dac_locals_dict_table[] = { // instance methods { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_dac_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_dac_deinit_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_dac_write_obj }, #if defined(TIM6) { MP_OBJ_NEW_QSTR(MP_QSTR_noise), (mp_obj_t)&pyb_dac_noise_obj }, diff --git a/stmhal/dma.c b/stmhal/dma.c index 2255e51601..9f3e87fb9e 100644 --- a/stmhal/dma.c +++ b/stmhal/dma.c @@ -33,11 +33,176 @@ #include "py/obj.h" #include "irq.h" -#define NSTREAMS_PER_CONTROLLER_LOG2 (3) -#define NSTREAMS_PER_CONTROLLER (1 << NSTREAMS_PER_CONTROLLER_LOG2) +typedef enum { + dma_id_not_defined=-1, + dma_id_0, + dma_id_1, + dma_id_2, + dma_id_3, + dma_id_4, + dma_id_5, + dma_id_6, + dma_id_7, + dma_id_8, + dma_id_9, + dma_id_10, + dma_id_11, + dma_id_12, + dma_id_13, + dma_id_14, + dma_id_15, +} dma_id_t; + +typedef struct _dma_descr_t { + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + DMA_Stream_TypeDef *instance; + #elif defined(MCU_SERIES_L4) + DMA_Channel_TypeDef *instance; + #else + #error "Unsupported Processor" + #endif + uint32_t sub_instance; + uint32_t transfer_direction; // periph to memory or vice-versa + dma_id_t id; + const DMA_InitTypeDef *init; +} dma_descr_t; + +// Default parameters to dma_init() shared by spi and i2c; Channel and Direction +// vary depending on the peripheral instance so they get passed separately +static const DMA_InitTypeDef dma_init_struct_spi_i2c = { + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + .Channel = 0, + #elif defined(MCU_SERIES_L4) + .Request = 0, + #endif + .Direction = 0, + .PeriphInc = DMA_PINC_DISABLE, + .MemInc = DMA_MINC_ENABLE, + .PeriphDataAlignment = DMA_PDATAALIGN_BYTE, + .MemDataAlignment = DMA_MDATAALIGN_BYTE, + .Mode = DMA_NORMAL, + .Priority = DMA_PRIORITY_LOW, + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + .FIFOMode = DMA_FIFOMODE_DISABLE, + .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, + .MemBurst = DMA_MBURST_INC4, + .PeriphBurst = DMA_PBURST_INC4 + #endif +}; + +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +// Parameters to dma_init() for SDIO tx and rx. +static const DMA_InitTypeDef dma_init_struct_sdio = { + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + .Channel = 0, + #elif defined(MCU_SERIES_L4) + .Request = 0, + #endif + .Direction = 0, + .PeriphInc = DMA_PINC_DISABLE, + .MemInc = DMA_MINC_ENABLE, + .PeriphDataAlignment = DMA_PDATAALIGN_WORD, + .MemDataAlignment = DMA_MDATAALIGN_WORD, + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + .Mode = DMA_PFCTRL, + #elif defined(MCU_SERIES_L4) + .Mode = DMA_NORMAL, + #endif + .Priority = DMA_PRIORITY_VERY_HIGH, + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + .FIFOMode = DMA_FIFOMODE_ENABLE, + .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, + .MemBurst = DMA_MBURST_INC4, + .PeriphBurst = DMA_PBURST_INC4, + #endif +}; +#endif + +#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) + .Channel = 0, + #elif defined(MCU_SERIES_L4) + .Request = 0, + #endif + .Direction = 0, + .PeriphInc = DMA_PINC_DISABLE, + .MemInc = DMA_MINC_ENABLE, + .PeriphDataAlignment = DMA_PDATAALIGN_BYTE, + .MemDataAlignment = DMA_MDATAALIGN_BYTE, + .Mode = DMA_NORMAL, + .Priority = DMA_PRIORITY_HIGH, + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + .FIFOMode = DMA_FIFOMODE_DISABLE, + .FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL, + .MemBurst = DMA_MBURST_SINGLE, + .PeriphBurst = DMA_PBURST_SINGLE, + #endif +}; +#endif + +#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (8) #define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) +#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (((dma_channel) & DMA_SxCR_CHSEL) >> 25) + +#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_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 }; +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 }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Stream2, DMA_CHANNEL_7, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +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(MICROPY_HW_ENABLE_DAC) && MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Stream5, DMA_CHANNEL_7, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_dac }; +const dma_descr_t dma_DAC_2_TX = { DMA1_Stream6, DMA_CHANNEL_7, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_3_TX = { DMA1_Stream7, DMA_CHANNEL_0, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Stream7, DMA_CHANNEL_1, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Stream7, DMA_CHANNEL_7, DMA_MEMORY_TO_PERIPH, dma_id_7, &dma_init_struct_spi_i2c }; +/* not preferred streams +const dma_descr_t dma_SPI_3_RX = { DMA1_Stream0, DMA_CHANNEL_0, DMA_PERIPH_TO_MEMORY, dma_id_0, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Stream6, DMA_CHANNEL_1, DMA_MEMORY_TO_PERIPH, dma_id_6, &dma_init_struct_spi_i2c }; +*/ + +// DMA2 streams +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 }; +const dma_descr_t dma_SPI_5_RX = { DMA2_Stream3, DMA_CHANNEL_2, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c }; +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDIO_0_RX= { DMA2_Stream3, DMA_CHANNEL_4, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_sdio }; +#endif +const dma_descr_t dma_SPI_4_RX = { DMA2_Stream3, DMA_CHANNEL_5, DMA_PERIPH_TO_MEMORY, dma_id_11, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_TX = { DMA2_Stream4, DMA_CHANNEL_2, DMA_MEMORY_TO_PERIPH, dma_id_12, &dma_init_struct_spi_i2c }; +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 }; +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 }; +#if defined(MICROPY_HW_HAS_SDCARD) && MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDIO_0_TX= { DMA2_Stream6, DMA_CHANNEL_4, DMA_MEMORY_TO_PERIPH, dma_id_14, &dma_init_struct_sdio }; +#endif +/* not preferred streams +const dma_descr_t dma_SPI_1_TX = { DMA2_Stream3, DMA_CHANNEL_3, DMA_MEMORY_TO_PERIPH, dma_id_11, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_1_RX = { DMA2_Stream0, DMA_CHANNEL_3, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_RX = { DMA2_Stream0, DMA_CHANNEL_4, DMA_PERIPH_TO_MEMORY, dma_id_8, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_4_TX = { DMA2_Stream1, DMA_CHANNEL_4, DMA_MEMORY_TO_PERIPH, dma_id_9, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_RX = { DMA2_Stream5, DMA_CHANNEL_7, DMA_PERIPH_TO_MEMORY, dma_id_13, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_5_TX = { DMA2_Stream6, DMA_CHANNEL_7, DMA_MEMORY_TO_PERIPH, dma_id_14, &dma_init_struct_spi_i2c }; +*/ + static const uint8_t dma_irqn[NSTREAM] = { DMA1_Stream0_IRQn, DMA1_Stream1_IRQn, @@ -57,71 +222,135 @@ static const uint8_t dma_irqn[NSTREAM] = { DMA2_Stream7_IRQn, }; -// Default parameters to dma_init() shared by spi and i2c; Channel and Direction -// vary depending on the peripheral instance so they get passed separately -const DMA_InitTypeDef dma_init_struct_spi_i2c = { - .Channel = 0, - .Direction = 0, - .PeriphInc = DMA_PINC_DISABLE, - .MemInc = DMA_MINC_ENABLE, - .PeriphDataAlignment = DMA_PDATAALIGN_BYTE, - .MemDataAlignment = DMA_MDATAALIGN_BYTE, - .Mode = DMA_NORMAL, - .Priority = DMA_PRIORITY_LOW, - .FIFOMode = DMA_FIFOMODE_DISABLE, - .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, - .MemBurst = DMA_MBURST_INC4, - .PeriphBurst = DMA_PBURST_INC4 +#elif defined(MCU_SERIES_L4) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (7) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_request) (dma_request) + +#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponfing to DMA1 +#define DMA2_ENABLE_MASK (0x3f80) // Bits in dma_enable_mask corresponding to DMA2 + +// These descriptors are ordered by DMAx_Channel number, and within a channel by request +// number. The duplicate streams are ok as long as they aren't used at the same time. + +// DMA1 streams +//const dma_descr_t dma_ADC_1_RX = { DMA1_Channel1, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_0, NULL }; // unused +//const dma_descr_t dma_ADC_2_RX = { DMA1_Channel2, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_1, NULL }; // unused +const dma_descr_t dma_SPI_1_RX = { DMA1_Channel2, DMA_REQUEST_1, DMA_PERIPH_TO_MEMORY, dma_id_1, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_TX = { DMA1_Channel2, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_1, &dma_init_struct_spi_i2c }; +//const dma_descr_t dma_ADC_3_RX = { DMA1_Channel3, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_2, NULL }; // unused +const dma_descr_t dma_SPI_1_TX = { DMA1_Channel3, DMA_REQUEST_1, DMA_MEMORY_TO_PERIPH, dma_id_2, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_3_RX = { DMA1_Channel3, DMA_REQUEST_3, DMA_PERIPH_TO_MEMORY, dma_id_2, &dma_init_struct_spi_i2c }; +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, DMA_REQUEST_6, DMA_MEMORY_TO_PERIPH, dma_id_2, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_RX = { DMA1_Channel4, DMA_REQUEST_1, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Channel4, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_3, &dma_init_struct_spi_i2c }; +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, DMA_REQUEST_5, DMA_MEMORY_TO_PERIPH, dma_id_3, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, DMA_REQUEST_1, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Channel5, DMA_REQUEST_3, DMA_PERIPH_TO_MEMORY, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Channel6, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_RX = { DMA1_Channel7, DMA_REQUEST_3, DMA_PERIPH_TO_MEMORY, dma_id_6, &dma_init_struct_spi_i2c }; + +// DMA2 streams +const dma_descr_t dma_SPI_3_RX = { DMA2_Channel1, DMA_REQUEST_3, DMA_PERIPH_TO_MEMORY, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_3_TX = { DMA2_Channel2, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_8, &dma_init_struct_spi_i2c }; +/* not preferred streams +const dma_descr_t dma_ADC_1_RX = { DMA2_Channel3, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_9, NULL }; +const dma_descr_t dma_SPI_1_RX = { DMA2_Channel3, DMA_REQUEST_4, DMA_PERIPH_TO_MEMORY, dma_id_9, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_ADC_2_RX = { DMA2_Channel4, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_10, NULL }; +const dma_descr_t dma_DAC_1_TX = { DMA2_Channel4, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_10, &dma_init_struct_dac }; +const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, DMA_REQUEST_4, DMA_MEMORY_TO_PERIPH, dma_id_10, &dma_init_struct_spi_i2c }; +*/ +#if MICROPY_HW_HAS_SDCARD +const dma_descr_t dma_SDIO_0_TX= { DMA2_Channel4, DMA_REQUEST_7, DMA_MEMORY_TO_PERIPH, dma_id_10, &dma_init_struct_sdio }; +#endif +/* not preferred streams +const dma_descr_t dma_ADC_3_RX = { DMA2_Channel5, DMA_REQUEST_0, DMA_PERIPH_TO_MEMORY, dma_id_11, NULL }; +const dma_descr_t dma_DAC_2_TX = { DMA2_Channel5, DMA_REQUEST_3, DMA_MEMORY_TO_PERIPH, dma_id_11, &dma_init_struct_dac }; +const dma_descr_t dma_SDIO_0_TX= { DMA2_Channel5, DMA_REQUEST_7, DMA_MEMORY_TO_PERIPH, dma_id_11, &dma_init_struct_sdio }; +const dma_descr_t dma_I2C_1_RX = { DMA2_Channel6, DMA_REQUEST_5, DMA_PERIPH_TO_MEMORY, dma_id_12, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA2_Channel7, DMA_REQUEST_5, DMA_MEMORY_TO_PERIPH, dma_id_13, &dma_init_struct_spi_i2c }; +*/ + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Channel1_IRQn, + DMA1_Channel2_IRQn, + DMA1_Channel3_IRQn, + DMA1_Channel4_IRQn, + DMA1_Channel5_IRQn, + DMA1_Channel6_IRQn, + DMA1_Channel7_IRQn, + DMA2_Channel1_IRQn, + DMA2_Channel2_IRQn, + DMA2_Channel3_IRQn, + DMA2_Channel4_IRQn, + DMA2_Channel5_IRQn, + DMA2_Channel6_IRQn, + DMA2_Channel7_IRQn, }; +#endif + static DMA_HandleTypeDef *dma_handle[NSTREAM] = {NULL}; -static uint8_t dma_last_channel[NSTREAM]; +static uint8_t dma_last_sub_instance[NSTREAM]; static volatile uint32_t dma_enable_mask = 0; - volatile dma_idle_count_t dma_idle; -#define DMA1_ENABLE_MASK 0x00ff // Bits in dma_enable_mask corresponfing to DMA1 -#define DMA2_ENABLE_MASK 0xff00 // Bits in dma_enable_mask corresponding to DMA2 #define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid -#define DMA_CHANNEL_AS_UINT8(dma_channel) (((dma_channel) & DMA_SxCR_CHSEL) >> 24) - -void DMA1_Stream0_IRQHandler(void) { IRQ_ENTER(DMA1_Stream0_IRQn); if (dma_handle[0] != NULL) { HAL_DMA_IRQHandler(dma_handle[0]); } IRQ_EXIT(DMA1_Stream0_IRQn); } -void DMA1_Stream1_IRQHandler(void) { IRQ_ENTER(DMA1_Stream1_IRQn); if (dma_handle[1] != NULL) { HAL_DMA_IRQHandler(dma_handle[1]); } IRQ_EXIT(DMA1_Stream1_IRQn); } -void DMA1_Stream2_IRQHandler(void) { IRQ_ENTER(DMA1_Stream2_IRQn); if (dma_handle[2] != NULL) { HAL_DMA_IRQHandler(dma_handle[2]); } IRQ_EXIT(DMA1_Stream2_IRQn); } -void DMA1_Stream3_IRQHandler(void) { IRQ_ENTER(DMA1_Stream3_IRQn); if (dma_handle[3] != NULL) { HAL_DMA_IRQHandler(dma_handle[3]); } IRQ_EXIT(DMA1_Stream3_IRQn); } -void DMA1_Stream4_IRQHandler(void) { IRQ_ENTER(DMA1_Stream4_IRQn); if (dma_handle[4] != NULL) { HAL_DMA_IRQHandler(dma_handle[4]); } IRQ_EXIT(DMA1_Stream4_IRQn); } -void DMA1_Stream5_IRQHandler(void) { IRQ_ENTER(DMA1_Stream5_IRQn); if (dma_handle[5] != NULL) { HAL_DMA_IRQHandler(dma_handle[5]); } IRQ_EXIT(DMA1_Stream5_IRQn); } -void DMA1_Stream6_IRQHandler(void) { IRQ_ENTER(DMA1_Stream6_IRQn); if (dma_handle[6] != NULL) { HAL_DMA_IRQHandler(dma_handle[6]); } IRQ_EXIT(DMA1_Stream6_IRQn); } -void DMA1_Stream7_IRQHandler(void) { IRQ_ENTER(DMA1_Stream7_IRQn); if (dma_handle[7] != NULL) { HAL_DMA_IRQHandler(dma_handle[7]); } IRQ_EXIT(DMA1_Stream7_IRQn); } -void DMA2_Stream0_IRQHandler(void) { IRQ_ENTER(DMA2_Stream0_IRQn); if (dma_handle[8] != NULL) { HAL_DMA_IRQHandler(dma_handle[8]); } IRQ_EXIT(DMA2_Stream0_IRQn); } -void DMA2_Stream1_IRQHandler(void) { IRQ_ENTER(DMA2_Stream1_IRQn); if (dma_handle[9] != NULL) { HAL_DMA_IRQHandler(dma_handle[9]); } IRQ_EXIT(DMA2_Stream1_IRQn); } -void DMA2_Stream2_IRQHandler(void) { IRQ_ENTER(DMA2_Stream2_IRQn); if (dma_handle[10] != NULL) { HAL_DMA_IRQHandler(dma_handle[10]); } IRQ_EXIT(DMA2_Stream2_IRQn); } -void DMA2_Stream3_IRQHandler(void) { IRQ_ENTER(DMA2_Stream3_IRQn); if (dma_handle[11] != NULL) { HAL_DMA_IRQHandler(dma_handle[11]); } IRQ_EXIT(DMA2_Stream3_IRQn); } -void DMA2_Stream4_IRQHandler(void) { IRQ_ENTER(DMA2_Stream4_IRQn); if (dma_handle[12] != NULL) { HAL_DMA_IRQHandler(dma_handle[12]); } IRQ_EXIT(DMA2_Stream4_IRQn); } -void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handle[13] != NULL) { HAL_DMA_IRQHandler(dma_handle[13]); } IRQ_EXIT(DMA2_Stream5_IRQn); } -void DMA2_Stream6_IRQHandler(void) { IRQ_ENTER(DMA2_Stream6_IRQn); if (dma_handle[14] != NULL) { HAL_DMA_IRQHandler(dma_handle[14]); } IRQ_EXIT(DMA2_Stream6_IRQn); } -void DMA2_Stream7_IRQHandler(void) { IRQ_ENTER(DMA2_Stream7_IRQn); if (dma_handle[15] != NULL) { HAL_DMA_IRQHandler(dma_handle[15]); } IRQ_EXIT(DMA2_Stream7_IRQn); } - #define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0) #define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0) -static int get_dma_id(DMA_Stream_TypeDef *dma_stream) { - int dma_id; - if (dma_stream < DMA2_Stream0) { - dma_id = dma_stream - DMA1_Stream0; - } else { - dma_id = NSTREAMS_PER_CONTROLLER + (dma_stream - DMA2_Stream0); - } - return dma_id; -} +#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + +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); } +void DMA1_Stream2_IRQHandler(void) { IRQ_ENTER(DMA1_Stream2_IRQn); if (dma_handle[dma_id_2] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_2]); } IRQ_EXIT(DMA1_Stream2_IRQn); } +void DMA1_Stream3_IRQHandler(void) { IRQ_ENTER(DMA1_Stream3_IRQn); if (dma_handle[dma_id_3] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_3]); } IRQ_EXIT(DMA1_Stream3_IRQn); } +void DMA1_Stream4_IRQHandler(void) { IRQ_ENTER(DMA1_Stream4_IRQn); if (dma_handle[dma_id_4] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_4]); } IRQ_EXIT(DMA1_Stream4_IRQn); } +void DMA1_Stream5_IRQHandler(void) { IRQ_ENTER(DMA1_Stream5_IRQn); if (dma_handle[dma_id_5] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_5]); } IRQ_EXIT(DMA1_Stream5_IRQn); } +void DMA1_Stream6_IRQHandler(void) { IRQ_ENTER(DMA1_Stream6_IRQn); if (dma_handle[dma_id_6] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_6]); } IRQ_EXIT(DMA1_Stream6_IRQn); } +void DMA1_Stream7_IRQHandler(void) { IRQ_ENTER(DMA1_Stream7_IRQn); if (dma_handle[dma_id_7] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_7]); } IRQ_EXIT(DMA1_Stream7_IRQn); } +void DMA2_Stream0_IRQHandler(void) { IRQ_ENTER(DMA2_Stream0_IRQn); if (dma_handle[dma_id_8] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_8]); } IRQ_EXIT(DMA2_Stream0_IRQn); } +void DMA2_Stream1_IRQHandler(void) { IRQ_ENTER(DMA2_Stream1_IRQn); if (dma_handle[dma_id_9] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_9]); } IRQ_EXIT(DMA2_Stream1_IRQn); } +void DMA2_Stream2_IRQHandler(void) { IRQ_ENTER(DMA2_Stream2_IRQn); if (dma_handle[dma_id_10] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_10]); } IRQ_EXIT(DMA2_Stream2_IRQn); } +void DMA2_Stream3_IRQHandler(void) { IRQ_ENTER(DMA2_Stream3_IRQn); if (dma_handle[dma_id_11] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_11]); } IRQ_EXIT(DMA2_Stream3_IRQn); } +void DMA2_Stream4_IRQHandler(void) { IRQ_ENTER(DMA2_Stream4_IRQn); if (dma_handle[dma_id_12] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_12]); } IRQ_EXIT(DMA2_Stream4_IRQn); } +void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handle[dma_id_13] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_13]); } IRQ_EXIT(DMA2_Stream5_IRQn); } +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) + +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); } +void DMA1_Channel3_IRQHandler(void) { IRQ_ENTER(DMA1_Channel3_IRQn); if (dma_handle[dma_id_2] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_2]); } IRQ_EXIT(DMA1_Channel3_IRQn); } +void DMA1_Channel4_IRQHandler(void) { IRQ_ENTER(DMA1_Channel4_IRQn); if (dma_handle[dma_id_3] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_3]); } IRQ_EXIT(DMA1_Channel4_IRQn); } +void DMA1_Channel5_IRQHandler(void) { IRQ_ENTER(DMA1_Channel5_IRQn); if (dma_handle[dma_id_4] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_4]); } IRQ_EXIT(DMA1_Channel5_IRQn); } +void DMA1_Channel6_IRQHandler(void) { IRQ_ENTER(DMA1_Channel6_IRQn); if (dma_handle[dma_id_5] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_5]); } IRQ_EXIT(DMA1_Channel6_IRQn); } +void DMA1_Channel7_IRQHandler(void) { IRQ_ENTER(DMA1_Channel7_IRQn); if (dma_handle[dma_id_6] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_6]); } IRQ_EXIT(DMA1_Channel7_IRQn); } +void DMA2_Channel1_IRQHandler(void) { IRQ_ENTER(DMA2_Channel1_IRQn); if (dma_handle[dma_id_7] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_7]); } IRQ_EXIT(DMA2_Channel1_IRQn); } +void DMA2_Channel2_IRQHandler(void) { IRQ_ENTER(DMA2_Channel2_IRQn); if (dma_handle[dma_id_8] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_8]); } IRQ_EXIT(DMA2_Channel2_IRQn); } +void DMA2_Channel3_IRQHandler(void) { IRQ_ENTER(DMA2_Channel3_IRQn); if (dma_handle[dma_id_9] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_9]); } IRQ_EXIT(DMA2_Channel3_IRQn); } +void DMA2_Channel4_IRQHandler(void) { IRQ_ENTER(DMA2_Channel4_IRQn); if (dma_handle[dma_id_10] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_10]);} IRQ_EXIT(DMA2_Channel4_IRQn); } +void DMA2_Channel5_IRQHandler(void) { IRQ_ENTER(DMA2_Channel5_IRQn); if (dma_handle[dma_id_11] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_11]);} IRQ_EXIT(DMA2_Channel5_IRQn); } +void DMA2_Channel6_IRQHandler(void) { IRQ_ENTER(DMA2_Channel6_IRQn); if (dma_handle[dma_id_12] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_12]);} IRQ_EXIT(DMA2_Channel6_IRQn); } +void DMA2_Channel7_IRQHandler(void) { IRQ_ENTER(DMA2_Channel7_IRQn); if (dma_handle[dma_id_13] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_13]);} IRQ_EXIT(DMA2_Channel7_IRQn); } + +#endif // Resets the idle counter for the DMA controller associated with dma_id. -static void dma_tickle(int dma_id) { - dma_idle.counter[(dma_id >> NSTREAMS_PER_CONTROLLER_LOG2) & 1] = 1; +static void dma_tickle(dma_id_t dma_id) { + dma_idle.counter[(dma_id < NSTREAMS_PER_CONTROLLER) ? 0 : 1] = 1; } -static void dma_enable_clock(int dma_id) { +static void dma_enable_clock(dma_id_t dma_id) { // We don't want dma_tick_handler() to turn off the clock right after we // enable it, so we need to mark the channel in use in an atomic fashion. mp_uint_t irq_state = MICROPY_BEGIN_ATOMIC_SECTION(); @@ -129,7 +358,7 @@ static void dma_enable_clock(int dma_id) { dma_enable_mask |= (1 << dma_id); MICROPY_END_ATOMIC_SECTION(irq_state); - if (dma_id <= 7) { + if (dma_id < NSTREAMS_PER_CONTROLLER) { if (((old_enable_mask & DMA1_ENABLE_MASK) == 0) && !DMA1_IS_CLK_ENABLED()) { __DMA1_CLK_ENABLE(); @@ -137,7 +366,7 @@ static void dma_enable_clock(int dma_id) { // in dma_last_channel (for DMA1) needs to be invalidated. for (int channel = 0; channel < NSTREAMS_PER_CONTROLLER; channel++) { - dma_last_channel[channel] = DMA_INVALID_CHANNEL; + dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL; } } } else { @@ -148,13 +377,13 @@ static void dma_enable_clock(int dma_id) { // in dma_last_channel (for DMA1) needs to be invalidated. for (int channel = NSTREAMS_PER_CONTROLLER; channel < NSTREAM; channel++) { - dma_last_channel[channel] = DMA_INVALID_CHANNEL; + dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL; } } } } -static void dma_disable_clock(int dma_id) { +static void dma_disable_clock(dma_id_t dma_id) { // We just mark the clock as disabled here, but we don't actually disable it. // We wait for the timer to expire first, which means that back-to-back // transfers don't have to initialize as much. @@ -162,61 +391,69 @@ static void dma_disable_clock(int dma_id) { dma_enable_mask &= ~(1 << dma_id); } -void dma_init(DMA_HandleTypeDef *dma, DMA_Stream_TypeDef *dma_stream, const DMA_InitTypeDef *dma_init, uint32_t dma_channel, uint32_t direction, void *data) { - int dma_id = get_dma_id(dma_stream); - //printf("dma_init(%p, %p(%d), 0x%x, 0x%x, %p)\n", dma, dma_stream, dma_id, (uint)dma_channel, (uint)direction, data); +void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data) { + // initialise parameters + dma->Instance = dma_descr->instance; + dma->Init = *dma_descr->init; + dma->Init.Direction = dma_descr->transfer_direction; + #if defined(MCU_SERIES_L4) + dma->Init.Request = dma_descr->sub_instance; + #else + dma->Init.Channel = dma_descr->sub_instance; + #endif + // half of __HAL_LINKDMA(data, xxx, *dma) + // caller must implement other half by doing: data->xxx = dma + dma->Parent = data; +} +void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){ // Some drivers allocate the DMA_HandleTypeDef from the stack // (i.e. dac, i2c, spi) and for those cases we need to clear the // structure so we don't get random values from the stack) memset(dma, 0, sizeof(*dma)); - // set global pointer for IRQ handler - dma_handle[dma_id] = dma; + if (dma_descr != NULL) { + dma_id_t dma_id = dma_descr->id; - // initialise parameters - dma->Instance = dma_stream; - dma->Init = *dma_init; - dma->Init.Direction = direction; - dma->Init.Channel = dma_channel; + dma_init_handle(dma, dma_descr, data); + // set global pointer for IRQ handler + dma_handle[dma_id] = dma; - // half of __HAL_LINKDMA(data, xxx, *dma) - // caller must implement other half by doing: data->xxx = dma - dma->Parent = data; + dma_enable_clock(dma_id); - dma_enable_clock(dma_id); + // if this stream was previously configured for this channel/request then we + // can skip most of the initialisation + uint8_t sub_inst = DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance); + if (dma_last_sub_instance[dma_id] != sub_inst) { + dma_last_sub_instance[dma_id] = sub_inst; - // if this stream was previously configured for this channel then we - // can skip most of the initialisation - uint8_t channel_uint8 = DMA_CHANNEL_AS_UINT8(dma_channel); - if (dma_last_channel[dma_id] == channel_uint8) { - goto same_channel; - } - dma_last_channel[dma_id] = channel_uint8; + // reset and configure DMA peripheral + if (HAL_DMA_GetState(dma) != HAL_DMA_STATE_RESET) { + HAL_DMA_DeInit(dma); + } + HAL_DMA_Init(dma); + HAL_NVIC_SetPriority(dma_irqn[dma_id], IRQ_PRI_DMA, IRQ_SUBPRI_DMA); + } - // reset and configure DMA peripheral - if (HAL_DMA_GetState(dma) != HAL_DMA_STATE_RESET) { - HAL_DMA_DeInit(dma); + HAL_NVIC_EnableIRQ(dma_irqn[dma_id]); } - HAL_DMA_Init(dma); - HAL_NVIC_SetPriority(dma_irqn[dma_id], IRQ_PRI_DMA, IRQ_SUBPRI_DMA); - -same_channel: - HAL_NVIC_EnableIRQ(dma_irqn[dma_id]); } -void dma_deinit(DMA_HandleTypeDef *dma) { - int dma_id = get_dma_id(dma->Instance); - HAL_NVIC_DisableIRQ(dma_irqn[dma_id]); - dma_handle[dma_id] = NULL; +void dma_deinit(const dma_descr_t *dma_descr) { + if (dma_descr != NULL) { + HAL_NVIC_DisableIRQ(dma_irqn[dma_descr->id]); + dma_handle[dma_descr->id] = NULL; - dma_disable_clock(dma_id); + dma_disable_clock(dma_descr->id); + } } -void dma_invalidate_channel(DMA_Stream_TypeDef *dma_stream, uint32_t dma_channel) { - int dma_id = get_dma_id(dma_stream); - if (dma_last_channel[dma_id] == DMA_CHANNEL_AS_UINT8(dma_channel)) { - dma_last_channel[dma_id] = DMA_INVALID_CHANNEL; +void dma_invalidate_channel(const dma_descr_t *dma_descr) { + if (dma_descr != NULL) { + dma_id_t dma_id = dma_descr->id; + if (dma_last_sub_instance[dma_id] == DMA_SUB_INSTANCE_AS_UINT8(dma_descr->sub_instance) ) { + dma_last_sub_instance[dma_id] = DMA_INVALID_CHANNEL; + } } } diff --git a/stmhal/dma.h b/stmhal/dma.h index 9561d1b529..5880029f3d 100644 --- a/stmhal/dma.h +++ b/stmhal/dma.h @@ -24,82 +24,58 @@ * THE SOFTWARE. */ -// These 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 - -#define DMA_STREAM_I2C1_RX DMA1_Stream0 -#define DMA_CHANNEL_I2C1_RX DMA_CHANNEL_1 - -#define DMA_STREAM_SPI3_RX DMA1_Stream2 -#define DMA_CHANNEL_SPI3_RX DMA_CHANNEL_0 - -#define DMA_STREAM_I2C3_RX DMA1_Stream2 -#define DMA_CHANNEL_I2C3_RX DMA_CHANNEL_3 - -#define DMA_STREAM_I2C2_RX DMA1_Stream2 -#define DMA_CHANNEL_I2C2_RX DMA_CHANNEL_7 - -#define DMA_STREAM_SPI2_RX DMA1_Stream3 -#define DMA_CHANNEL_SPI2_RX DMA_CHANNEL_0 - -#define DMA_STREAM_SPI2_TX DMA1_Stream4 -#define DMA_CHANNEL_SPI2_TX DMA_CHANNEL_0 - -#define DMA_STREAM_I2C3_TX DMA1_Stream4 -#define DMA_CHANNEL_I2C3_TX DMA_CHANNEL_3 - -#define DMA_STREAM_DAC1 DMA1_Stream5 -#define DMA_CHANNEL_DAC1 DMA_CHANNEL_7 - -#define DMA_STREAM_DAC2 DMA1_Stream6 -#define DMA_CHANNEL_DAC2 DMA_CHANNEL_7 - -#define DMA_STREAM_SPI3_TX DMA1_Stream7 -#define DMA_CHANNEL_SPI3_TX DMA_CHANNEL_0 - -#define DMA_STREAM_I2C1_TX DMA1_Stream7 -#define DMA_CHANNEL_I2C1_TX DMA_CHANNEL_1 - -#define DMA_STREAM_I2C2_TX DMA1_Stream7 -#define DMA_CHANNEL_I2C2_TX DMA_CHANNEL_7 - -// DMA2 streams - -#define DMA_STREAM_SPI1_RX DMA2_Stream2 -#define DMA_CHANNEL_SPI1_RX DMA_CHANNEL_3 - -#define DMA_STREAM_SPI5_RX DMA2_Stream3 -#define DMA_CHANNEL_SPI5_RX DMA_CHANNEL_2 - -#define DMA_STREAM_SDIO_RX DMA2_Stream3 -#define DMA_CHANNEL_SDIO_RX DMA_CHANNEL_4 - -#define DMA_STREAM_SPI4_RX DMA2_Stream3 -#define DMA_CHANNEL_SPI4_RX DMA_CHANNEL_5 - -#define DMA_STREAM_SPI5_TX DMA2_Stream4 -#define DMA_CHANNEL_SPI5_TX DMA_CHANNEL_2 - -#define DMA_STREAM_SPI4_TX DMA2_Stream4 -#define DMA_CHANNEL_SPI4_TX DMA_CHANNEL_5 - -#define DMA_STREAM_SPI6_TX DMA2_Stream5 -#define DMA_CHANNEL_SPI6_TX DMA_CHANNEL_1 - -#define DMA_STREAM_SPI1_TX DMA2_Stream5 -#define DMA_CHANNEL_SPI1_TX DMA_CHANNEL_3 - -#define DMA_STREAM_SPI6_RX DMA2_Stream6 -#define DMA_CHANNEL_SPI6_RX DMA_CHANNEL_1 - -#define DMA_STREAM_SDIO_TX DMA2_Stream6 -#define DMA_CHANNEL_SDIO_TX DMA_CHANNEL_4 +#ifndef __MICROPY_INCLUDED_STMHAL_DMA_H__ +#define __MICROPY_INCLUDED_STMHAL_DMA_H__ + +typedef struct _dma_descr_t dma_descr_t; + +#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + +extern const dma_descr_t dma_I2C_1_RX; +extern const dma_descr_t dma_SPI_3_RX; +extern const dma_descr_t dma_I2C_3_RX; +extern const dma_descr_t dma_I2C_2_RX; +extern const dma_descr_t dma_SPI_2_RX; +extern const dma_descr_t dma_SPI_2_TX; +extern const dma_descr_t dma_I2C_3_TX; +extern const dma_descr_t dma_DAC_1_TX; +extern const dma_descr_t dma_DAC_2_TX; +extern const dma_descr_t dma_SPI_3_TX; +extern const dma_descr_t dma_I2C_1_TX; +extern const dma_descr_t dma_I2C_2_TX; +extern const dma_descr_t dma_SPI_1_RX; +extern const dma_descr_t dma_SPI_5_RX; +extern const dma_descr_t dma_SDIO_0_RX; +extern const dma_descr_t dma_SPI_4_RX; +extern const dma_descr_t dma_SPI_5_TX; +extern const dma_descr_t dma_SPI_4_TX; +extern const dma_descr_t dma_SPI_6_TX; +extern const dma_descr_t dma_SPI_1_TX; +extern const dma_descr_t dma_SPI_6_RX; +extern const dma_descr_t dma_SDIO_0_TX; + +#elif defined(MCU_SERIES_L4) + +extern const dma_descr_t dma_ADC_1_RX; +extern const dma_descr_t dma_ADC_2_RX; +extern const dma_descr_t dma_SPI_1_RX; +extern const dma_descr_t dma_I2C_3_TX; +extern const dma_descr_t dma_ADC_3_RX; +extern const dma_descr_t dma_SPI_1_TX; +extern const dma_descr_t dma_I2C_3_RX; +extern const dma_descr_t dma_DAC_1_TX; +extern const dma_descr_t dma_SPI_2_RX; +extern const dma_descr_t dma_I2C_2_TX; +extern const dma_descr_t dma_DAC_2_TX; +extern const dma_descr_t dma_SPI_2_TX; +extern const dma_descr_t dma_I2C_2_RX; +extern const dma_descr_t dma_I2C_1_TX; +extern const dma_descr_t dma_I2C_1_RX; +extern const dma_descr_t dma_SPI_3_RX; +extern const dma_descr_t dma_SPI_3_TX; +extern const dma_descr_t dma_SDIO_1_TX; + +#endif typedef union { uint16_t enabled; // Used to test if both counters are == 0 @@ -113,9 +89,11 @@ extern volatile dma_idle_count_t dma_idle; #define DMA_IDLE_TICK_MAX (8) // 128 msec #define DMA_IDLE_TICK(tick) (((tick) & DMA_SYSTICK_MASK) == 0) -extern const DMA_InitTypeDef dma_init_struct_spi_i2c; -void dma_init(DMA_HandleTypeDef *dma, DMA_Stream_TypeDef *dma_stream, const DMA_InitTypeDef *dma_init, uint32_t dma_channel, uint32_t direction, void *data); -void dma_deinit(DMA_HandleTypeDef *dma); -void dma_invalidate_channel(DMA_Stream_TypeDef *dma_stream, uint32_t dma_channel); +void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data); +void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data); +void dma_deinit(const dma_descr_t *dma_descr); +void dma_invalidate_channel(const dma_descr_t *dma_descr); void dma_idle_handler(int controller); + +#endif //__MICROPY_INCLUDED_STMHAL_DMA_H__ diff --git a/stmhal/i2c.c b/stmhal/i2c.c index 9f6506b017..1909f81606 100644 --- a/stmhal/i2c.c +++ b/stmhal/i2c.c @@ -101,25 +101,14 @@ /// i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42, /// # starting at address 2 in the slave /// i2c.mem_write('abc', 0x42, 2, timeout=1000) - -// Possible DMA configurations for I2C busses: -// I2C1_TX: DMA1_Stream6.CHANNEL_1 or DMA1_Stream7.CHANNEL_1 -// I2C1_RX: DMA1_Stream0.CHANNEL_1 or DMA1_Stream5.CHANNEL_1 -// I2C2_TX: DMA1_Stream7.CHANNEL_7 -// I2C2_RX: DMA1_Stream2.CHANNEL_7 or DMA1_Stream3.CHANNEL_7 -// I2C3_TX: DMA1_Stream4.CHANNEL_3 -// I2C3_RX: DMA1_Stream2.CHANNEL_3 - #define PYB_I2C_MASTER (0) #define PYB_I2C_SLAVE (1) typedef struct _pyb_i2c_obj_t { mp_obj_base_t base; I2C_HandleTypeDef *i2c; - DMA_Stream_TypeDef *tx_dma_stream; - uint32_t tx_dma_channel; - DMA_Stream_TypeDef *rx_dma_stream; - uint32_t rx_dma_channel; + const dma_descr_t *tx_dma_descr; + const dma_descr_t *rx_dma_descr; } pyb_i2c_obj_t; #if defined(MICROPY_HW_I2C1_SCL) @@ -134,24 +123,24 @@ I2C_HandleTypeDef I2CHandle3 = {.Instance = NULL}; STATIC const pyb_i2c_obj_t pyb_i2c_obj[] = { #if defined(MICROPY_HW_I2C1_SCL) - {{&pyb_i2c_type}, &I2CHandle1, DMA_STREAM_I2C1_TX, DMA_CHANNEL_I2C1_TX, DMA_STREAM_I2C1_RX, DMA_CHANNEL_I2C1_RX}, + {{&pyb_i2c_type}, &I2CHandle1, &dma_I2C_1_TX, &dma_I2C_1_RX}, #else - {{&pyb_i2c_type}, NULL, NULL, 0, NULL, 0}, + {{&pyb_i2c_type}, NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C2_SCL) - {{&pyb_i2c_type}, &I2CHandle2, DMA_STREAM_I2C2_TX, DMA_CHANNEL_I2C2_TX, DMA_STREAM_I2C2_RX, DMA_CHANNEL_I2C2_RX}, + {{&pyb_i2c_type}, &I2CHandle2, &dma_I2C_2_TX, &dma_I2C_2_RX}, #else - {{&pyb_i2c_type}, NULL, NULL, 0, NULL, 0}, + {{&pyb_i2c_type}, NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_I2C3_SCL) - {{&pyb_i2c_type}, &I2CHandle3, DMA_STREAM_I2C3_TX, DMA_CHANNEL_I2C3_TX, DMA_STREAM_I2C3_RX, DMA_CHANNEL_I2C3_RX}, + {{&pyb_i2c_type}, &I2CHandle3, &dma_I2C_3_TX, &dma_I2C_3_RX}, #else - {{&pyb_i2c_type}, NULL, NULL, 0, NULL, 0}, + {{&pyb_i2c_type}, NULL, NULL, NULL}, #endif }; #if defined(MICROPY_HW_I2C_BAUDRATE_TIMING) -// The STM32F0, F3, and F7 use a TIMINGR register rather than ClockSpeed and +// The STM32F0, F3, F7 and L4 use a TIMINGR register rather than ClockSpeed and // DutyCycle. STATIC const struct { @@ -263,8 +252,8 @@ void i2c_init(I2C_HandleTypeDef *i2c) { // invalidate the DMA channels so they are initialised on first use const pyb_i2c_obj_t *self = &pyb_i2c_obj[i2c_unit - 1]; - dma_invalidate_channel(self->tx_dma_stream, self->tx_dma_channel); - dma_invalidate_channel(self->rx_dma_stream, self->rx_dma_channel); + dma_invalidate_channel(self->tx_dma_descr); + dma_invalidate_channel(self->rx_dma_descr); } void i2c_deinit(I2C_HandleTypeDef *i2c) { @@ -528,7 +517,7 @@ STATIC mp_obj_t pyb_i2c_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ // if IRQs are enabled then we can use DMA DMA_HandleTypeDef tx_dma; if (query_irq() == IRQ_STATE_ENABLED) { - dma_init(&tx_dma, self->tx_dma_stream, &dma_init_struct_spi_i2c, self->tx_dma_channel, DMA_MEMORY_TO_PERIPH, self->i2c); + dma_init(&tx_dma, self->tx_dma_descr, self->i2c); self->i2c->hdmatx = &tx_dma; self->i2c->hdmarx = NULL; } @@ -538,7 +527,7 @@ STATIC mp_obj_t pyb_i2c_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ if (in_master_mode(self)) { if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) { if (query_irq() == IRQ_STATE_ENABLED) { - dma_deinit(&tx_dma); + dma_deinit(self->tx_dma_descr); } nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "addr argument required")); } @@ -561,7 +550,7 @@ STATIC mp_obj_t pyb_i2c_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ if (status == HAL_OK) { status = i2c_wait_dma_finished(self->i2c, args[2].u_int); } - dma_deinit(&tx_dma); + dma_deinit(self->tx_dma_descr); } if (status != HAL_OK) { @@ -602,7 +591,7 @@ STATIC mp_obj_t pyb_i2c_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ // if IRQs are enabled then we can use DMA DMA_HandleTypeDef rx_dma; if (query_irq() == IRQ_STATE_ENABLED) { - dma_init(&rx_dma, self->rx_dma_stream, &dma_init_struct_spi_i2c, self->rx_dma_channel, DMA_PERIPH_TO_MEMORY, self->i2c); + dma_init(&rx_dma, self->rx_dma_descr, self->i2c); self->i2c->hdmatx = NULL; self->i2c->hdmarx = &rx_dma; } @@ -632,7 +621,7 @@ STATIC mp_obj_t pyb_i2c_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ if (status == HAL_OK) { status = i2c_wait_dma_finished(self->i2c, args[2].u_int); } - dma_deinit(&rx_dma); + dma_deinit(self->rx_dma_descr); } if (status != HAL_OK) { @@ -696,14 +685,14 @@ STATIC mp_obj_t pyb_i2c_mem_read(mp_uint_t n_args, const mp_obj_t *pos_args, mp_ status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len, args[3].u_int); } else { DMA_HandleTypeDef rx_dma; - dma_init(&rx_dma, self->rx_dma_stream, &dma_init_struct_spi_i2c, self->rx_dma_channel, DMA_PERIPH_TO_MEMORY, self->i2c); + dma_init(&rx_dma, self->rx_dma_descr, self->i2c); self->i2c->hdmatx = NULL; self->i2c->hdmarx = &rx_dma; status = HAL_I2C_Mem_Read_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len); if (status == HAL_OK) { status = i2c_wait_dma_finished(self->i2c, args[3].u_int); } - dma_deinit(&rx_dma); + dma_deinit(self->rx_dma_descr); } if (status != HAL_OK) { @@ -760,14 +749,14 @@ STATIC mp_obj_t pyb_i2c_mem_write(mp_uint_t n_args, const mp_obj_t *pos_args, mp status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len, args[3].u_int); } else { DMA_HandleTypeDef tx_dma; - dma_init(&tx_dma, self->tx_dma_stream, &dma_init_struct_spi_i2c, self->tx_dma_channel, DMA_MEMORY_TO_PERIPH, self->i2c); + dma_init(&tx_dma, self->tx_dma_descr, self->i2c); self->i2c->hdmatx = &tx_dma; self->i2c->hdmarx = NULL; status = HAL_I2C_Mem_Write_DMA(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len); if (status == HAL_OK) { status = i2c_wait_dma_finished(self->i2c, args[3].u_int); } - dma_deinit(&tx_dma); + dma_deinit(self->tx_dma_descr); } if (status != HAL_OK) { diff --git a/stmhal/i2c.h b/stmhal/i2c.h index 849d3987c4..a159935e6a 100644 --- a/stmhal/i2c.h +++ b/stmhal/i2c.h @@ -29,6 +29,7 @@ extern I2C_HandleTypeDef I2CHandle1; extern I2C_HandleTypeDef I2CHandle2; +extern I2C_HandleTypeDef I2CHandle3; extern const mp_obj_type_t pyb_i2c_type; void i2c_init0(void); diff --git a/stmhal/led.c b/stmhal/led.c index fcdb88c9c3..fdf5b04d8e 100644 --- a/stmhal/led.c +++ b/stmhal/led.c @@ -41,6 +41,11 @@ /// /// The LED object controls an individual LED (Light Emitting Diode). +// the default is that LEDs are not inverted, and pin driven high turns them on +#ifndef MICROPY_HW_LED_INVERTED +#define MICROPY_HW_LED_INVERTED (0) +#endif + typedef struct _pyb_led_obj_t { mp_obj_base_t base; mp_uint_t led_id; @@ -86,30 +91,34 @@ void led_init(void) { || defined(MICROPY_HW_LED4_PWM) // The following is semi-generic code to control LEDs using PWM. -// It currently supports TIM2 and TIM3, channel 1 only. +// It currently supports TIM1, TIM2 and TIM3, channels 1-4. // Configure by defining the relevant MICROPY_HW_LEDx_PWM macros in mpconfigboard.h. // If they are not defined then PWM will not be available for that LED. #define LED_PWM_ENABLED (1) #ifndef MICROPY_HW_LED1_PWM -#define MICROPY_HW_LED1_PWM { NULL, 0, 0 } +#define MICROPY_HW_LED1_PWM { NULL, 0, 0, 0 } #endif #ifndef MICROPY_HW_LED2_PWM -#define MICROPY_HW_LED2_PWM { NULL, 0, 0 } +#define MICROPY_HW_LED2_PWM { NULL, 0, 0, 0 } #endif #ifndef MICROPY_HW_LED3_PWM -#define MICROPY_HW_LED3_PWM { NULL, 0, 0 } +#define MICROPY_HW_LED3_PWM { NULL, 0, 0, 0 } #endif #ifndef MICROPY_HW_LED4_PWM -#define MICROPY_HW_LED4_PWM { NULL, 0, 0 } +#define MICROPY_HW_LED4_PWM { NULL, 0, 0, 0 } #endif #define LED_PWM_TIM_PERIOD (10000) // TIM runs at 1MHz and fires every 10ms +// this gives the address of the CCR register for channels 1-4 +#define LED_PWM_CCR(pwm_cfg) ((volatile uint32_t*)&(pwm_cfg)->tim->CCR1 + ((pwm_cfg)->tim_channel >> 2)) + typedef struct _led_pwm_config_t { TIM_TypeDef *tim; uint8_t tim_id; + uint8_t tim_channel; uint8_t alt_func; } led_pwm_config_t; @@ -143,6 +152,7 @@ STATIC void led_pwm_init(int led) { // TIM configuration switch (pwm_cfg->tim_id) { + case 1: __TIM1_CLK_ENABLE(); break; case 2: __TIM2_CLK_ENABLE(); break; case 3: __TIM3_CLK_ENABLE(); break; default: assert(0); @@ -153,21 +163,20 @@ STATIC void led_pwm_init(int led) { tim.Init.Prescaler = timer_get_source_freq(pwm_cfg->tim_id) / 1000000 - 1; // TIM runs at 1MHz tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; tim.Init.CounterMode = TIM_COUNTERMODE_UP; + tim.Init.RepetitionCounter = 0; HAL_TIM_PWM_Init(&tim); - // PWM configuration (only channel 1 supported at the moment) + // PWM configuration TIM_OC_InitTypeDef oc_init; oc_init.OCMode = TIM_OCMODE_PWM1; oc_init.Pulse = 0; // off - oc_init.OCPolarity = TIM_OCPOLARITY_HIGH; + oc_init.OCPolarity = MICROPY_HW_LED_INVERTED ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH; oc_init.OCFastMode = TIM_OCFAST_DISABLE; - /* needed only for TIM1 and TIM8 - oc_init.OCNPolarity = TIM_OCNPOLARITY_HIGH; - oc_init.OCIdleState = TIM_OCIDLESTATE_SET; - oc_init.OCNIdleState = TIM_OCNIDLESTATE_SET; - */ - HAL_TIM_PWM_ConfigChannel(&tim, &oc_init, TIM_CHANNEL_1); - HAL_TIM_PWM_Start(&tim, TIM_CHANNEL_1); + oc_init.OCNPolarity = TIM_OCNPOLARITY_HIGH; // needed for TIM1 and TIM8 + oc_init.OCIdleState = TIM_OCIDLESTATE_SET; // needed for TIM1 and TIM8 + oc_init.OCNIdleState = TIM_OCNIDLESTATE_SET; // needed for TIM1 and TIM8 + HAL_TIM_PWM_ConfigChannel(&tim, &oc_init, pwm_cfg->tim_channel); + HAL_TIM_PWM_Start(&tim, pwm_cfg->tim_channel); // indicate that this LED is using PWM led_pwm_state |= 1 << led; @@ -236,8 +245,8 @@ int led_get_intensity(pyb_led_t led) { #if LED_PWM_ENABLED if (led_pwm_is_enabled(led)) { - TIM_TypeDef *tim = led_pwm_config[led - 1].tim; - mp_uint_t i = (tim->CCR1 * 255 + LED_PWM_TIM_PERIOD - 2) / (LED_PWM_TIM_PERIOD - 1); + const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1]; + mp_uint_t i = (*LED_PWM_CCR(pwm_cfg) * 255 + LED_PWM_TIM_PERIOD - 2) / (LED_PWM_TIM_PERIOD - 1); if (i > 255) { i = 255; } @@ -248,26 +257,25 @@ int led_get_intensity(pyb_led_t led) { const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; GPIO_TypeDef *gpio = led_pin->gpio; - // TODO convert high/low to on/off depending on board if (gpio->ODR & led_pin->pin_mask) { // pin is high - return 255; + return MICROPY_HW_LED_INVERTED ? 0 : 255; } else { // pin is low - return 0; + return MICROPY_HW_LED_INVERTED ? 255 : 0; } } void led_set_intensity(pyb_led_t led, mp_int_t intensity) { #if LED_PWM_ENABLED if (intensity > 0 && intensity < 255) { - TIM_TypeDef *tim = led_pwm_config[led - 1].tim; - if (tim != NULL) { + const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1]; + if (pwm_cfg->tim != NULL) { // set intensity using PWM pulse width if (!led_pwm_is_enabled(led)) { led_pwm_init(led); } - tim->CCR1 = intensity * (LED_PWM_TIM_PERIOD - 1) / 255; + *LED_PWM_CCR(pwm_cfg) = intensity * (LED_PWM_TIM_PERIOD - 1) / 255; return; } } diff --git a/stmhal/main.c b/stmhal/main.c index 329109cd3d..30dddaf989 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -367,13 +367,15 @@ int main(void) { __GPIOC_CLK_ENABLE(); __GPIOD_CLK_ENABLE(); - #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. - __HAL_RCC_DTCMRAMEN_CLK_ENABLE(); - #else - // enable the CCM RAM - __CCMDATARAMEN_CLK_ENABLE(); + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + #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. + __HAL_RCC_DTCMRAMEN_CLK_ENABLE(); + #else + // enable the CCM RAM + __CCMDATARAMEN_CLK_ENABLE(); + #endif #endif #if defined(MICROPY_BOARD_EARLY_INIT) diff --git a/stmhal/modmachine.c b/stmhal/modmachine.c index 1e4862044a..0b01058fa5 100644 --- a/stmhal/modmachine.c +++ b/stmhal/modmachine.c @@ -190,6 +190,10 @@ STATIC mp_obj_t machine_freq(mp_uint_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) + nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, "machine.freq set not supported yet")); + #endif + // default PLL parameters that give 48MHz on PLL48CK uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7; uint32_t sysclk_source; @@ -310,9 +314,12 @@ STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) { // set PLL as system clock source if wanted if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) { + #if !defined(MICROPY_HW_FLASH_LATENCY) + #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5 + #endif RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, MICROPY_HW_FLASH_LATENCY) != HAL_OK) { goto fail; } } @@ -344,6 +351,35 @@ STATIC mp_obj_t machine_freq(mp_uint_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) + + // Enter Stop 1 mode + __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); + HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); + + // reconfigure system clock after wakeup + // Enable Power Control clock + __HAL_RCC_PWR_CLK_ENABLE(); + + // Get the Oscillators configuration according to the internal RCC registers + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + HAL_RCC_GetOscConfig(&RCC_OscInitStruct); + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + HAL_RCC_OscConfig(&RCC_OscInitStruct); + + // Get the Clocks configuration according to the internal RCC registers + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + uint32_t pFLatency = 0; + HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency); + + // Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clock dividers + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency); + + #else + // takes longer to wake but reduces stop current HAL_PWREx_EnableFlashPowerDown(); @@ -366,6 +402,8 @@ STATIC mp_obj_t machine_sleep(void) { while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL) { } + #endif + return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); @@ -373,7 +411,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_F7) +#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) printf("machine.deepsleep not supported yet\n"); #else // We need to clear the PWR wake-up-flag before entering standby, since diff --git a/stmhal/modnetwork.c b/stmhal/modnetwork.c index 86bf7379bb..4425461a07 100644 --- a/stmhal/modnetwork.c +++ b/stmhal/modnetwork.c @@ -27,7 +27,6 @@ #include <stdio.h> #include <stdint.h> #include <string.h> -#include <errno.h> #include "py/nlr.h" #include "py/objlist.h" diff --git a/stmhal/modnwcc3k.c b/stmhal/modnwcc3k.c index 85dc0585a8..5910576029 100644 --- a/stmhal/modnwcc3k.c +++ b/stmhal/modnwcc3k.c @@ -26,7 +26,6 @@ #include <string.h> #include <stdarg.h> -#include <errno.h> // CC3000 defines its own ENOBUFS (different to standard one!) #undef ENOBUFS @@ -36,6 +35,7 @@ #include "py/objlist.h" #include "py/stream.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "netutils.h" #include "modnetwork.h" #include "pin.h" @@ -126,7 +126,7 @@ STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uin if (ip == 0) { // unknown host - return ENOENT; + return MP_ENOENT; } out_ip[0] = ip >> 24; @@ -139,7 +139,7 @@ STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uin STATIC int cc3k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { if (socket->u_param.domain != MOD_NETWORK_AF_INET) { - *_errno = EAFNOSUPPORT; + *_errno = MP_EAFNOSUPPORT; return -1; } @@ -148,7 +148,7 @@ STATIC int cc3k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { case MOD_NETWORK_SOCK_STREAM: type = SOCK_STREAM; break; case MOD_NETWORK_SOCK_DGRAM: type = SOCK_DGRAM; break; case MOD_NETWORK_SOCK_RAW: type = SOCK_RAW; break; - default: *_errno = EINVAL; return -1; + default: *_errno = MP_EINVAL; return -1; } // open socket @@ -202,7 +202,7 @@ STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_sock socklen_t addr_len = sizeof(addr); if ((fd = CC3000_EXPORT(accept)(socket->u_state, &addr, &addr_len)) < 0) { if (fd == SOC_IN_PROGRESS) { - *_errno = EAGAIN; + *_errno = MP_EAGAIN; } else { *_errno = -fd; } @@ -240,7 +240,7 @@ STATIC int cc3k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_ui STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { if (cc3k_get_fd_closed_state(socket->u_state)) { CC3000_EXPORT(closesocket)(socket->u_state); - *_errno = EPIPE; + *_errno = MP_EPIPE; return -1; } @@ -267,7 +267,7 @@ STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, m fd_set rfds; FD_ZERO(&rfds); FD_SET(socket->u_state, &rfds); - timeval tv; + cc3000_timeval tv; tv.tv_sec = 0; tv.tv_usec = 1; int nfds = CC3000_EXPORT(select)(socket->u_state + 1, &rfds, NULL, NULL, &tv); @@ -383,7 +383,7 @@ STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request } // call cc3000 select with minimum timeout - timeval tv; + cc3000_timeval tv; tv.tv_sec = 0; tv.tv_usec = 1; int nfds = CC3000_EXPORT(select)(fd + 1, &rfds, &wfds, &xfds, &tv); @@ -405,7 +405,7 @@ STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request ret |= MP_IOCTL_POLL_HUP; } } else { - *_errno = EINVAL; + *_errno = MP_EINVAL; ret = -1; } return ret; diff --git a/stmhal/modnwwiznet5k.c b/stmhal/modnwwiznet5k.c index b6f18354b9..c8b5d628f4 100644 --- a/stmhal/modnwwiznet5k.c +++ b/stmhal/modnwwiznet5k.c @@ -27,11 +27,11 @@ #include <stdio.h> #include <stdint.h> #include <string.h> -#include <errno.h> #include "py/nlr.h" #include "py/objlist.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "netutils.h" #include "modnetwork.h" @@ -93,20 +93,20 @@ STATIC int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, return 0; } else { // failure - return ENOENT; + return MP_ENOENT; } } STATIC int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { if (socket->u_param.domain != MOD_NETWORK_AF_INET) { - *_errno = EAFNOSUPPORT; + *_errno = MP_EAFNOSUPPORT; return -1; } switch (socket->u_param.type) { case MOD_NETWORK_SOCK_STREAM: socket->u_param.type = Sn_MR_TCP; break; case MOD_NETWORK_SOCK_DGRAM: socket->u_param.type = Sn_MR_UDP; break; - default: *_errno = EINVAL; return -1; + default: *_errno = MP_EINVAL; return -1; } if (socket->u_param.fileno == -1) { @@ -120,7 +120,7 @@ STATIC int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) } if (socket->u_param.fileno == -1) { // too many open sockets - *_errno = EMFILE; + *_errno = MP_EMFILE; return -1; } } @@ -199,7 +199,7 @@ STATIC int wiznet5k_socket_accept(mod_network_socket_obj_t *socket, mod_network_ } if (sr == SOCK_CLOSED || sr == SOCK_CLOSE_WAIT) { wiznet5k_socket_close(socket); - *_errno = ENOTCONN; // ?? + *_errno = MP_ENOTCONN; // ?? return -1; } HAL_Delay(1); @@ -277,13 +277,13 @@ STATIC mp_uint_t wiznet5k_socket_recvfrom(mod_network_socket_obj_t *socket, byte STATIC int wiznet5k_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { // TODO - *_errno = EINVAL; + *_errno = MP_EINVAL; return -1; } STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) { // TODO - *_errno = EINVAL; + *_errno = MP_EINVAL; return -1; /* @@ -297,7 +297,7 @@ STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_ STATIC int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) { // TODO - *_errno = EINVAL; + *_errno = MP_EINVAL; return -1; } diff --git a/stmhal/moduos.c b/stmhal/moduos.c index 310b8d44fb..52d0a58425 100644 --- a/stmhal/moduos.c +++ b/stmhal/moduos.c @@ -107,7 +107,7 @@ STATIC mp_obj_t os_getcwd(void) { FRESULT res = f_getcwd(buf, sizeof buf); if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } return mp_obj_new_str(buf, strlen(buf), false); diff --git a/stmhal/moduselect.c b/stmhal/moduselect.c index 8923b4d505..e87478ae62 100644 --- a/stmhal/moduselect.c +++ b/stmhal/moduselect.c @@ -25,11 +25,11 @@ */ #include <stdio.h> -#include <errno.h> #include "py/nlr.h" #include "py/obj.h" #include "py/objlist.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "pybioctl.h" @@ -212,7 +212,7 @@ STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmas mp_obj_poll_t *self = self_in; mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP); if (elem == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOENT))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOENT))); } ((poll_obj_t*)elem->value)->flags = mp_obj_get_int(eventmask_in); return mp_const_none; diff --git a/stmhal/modusocket.c b/stmhal/modusocket.c index 8da56fa8bb..9cc1f3314a 100644 --- a/stmhal/modusocket.c +++ b/stmhal/modusocket.c @@ -26,12 +26,12 @@ #include <stdio.h> #include <string.h> -#include <errno.h> #include "py/nlr.h" #include "py/objtuple.h" #include "py/objlist.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "netutils.h" #include "modnetwork.h" @@ -116,7 +116,7 @@ STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) { if (self->nic == MP_OBJ_NULL) { // not connected // TODO I think we can listen even if not bound... - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOTCONN))); } int _errno; @@ -186,7 +186,7 @@ STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { mod_network_socket_obj_t *self = self_in; if (self->nic == MP_OBJ_NULL) { // not connected - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EPIPE))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EPIPE))); } mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); @@ -204,7 +204,7 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { mod_network_socket_obj_t *self = self_in; if (self->nic == MP_OBJ_NULL) { // not connected - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOTCONN))); } mp_int_t len = mp_obj_get_int(len_in); vstr_t vstr; @@ -253,7 +253,7 @@ STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { mod_network_socket_obj_t *self = self_in; if (self->nic == MP_OBJ_NULL) { // not connected - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOTCONN))); } vstr_t vstr; vstr_init_len(&vstr, mp_obj_get_int(len_in)); @@ -314,7 +314,7 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { mod_network_socket_obj_t *self = self_in; if (self->nic == MP_OBJ_NULL) { // not connected - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOTCONN))); } mp_uint_t timeout; if (timeout_in == mp_const_none) { diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 6ec92acbfe..29e4bd8d87 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -61,6 +61,7 @@ #define MICROPY_STREAMS_NON_BLOCK (1) #define MICROPY_MODULE_WEAK_LINKS (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_USE_INTERNAL_ERRNO (1) #define MICROPY_PY_FUNCTION_ATTRS (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) @@ -80,6 +81,7 @@ #define MICROPY_PY_CMATH (1) #define MICROPY_PY_IO (1) #define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_UERRNO (1) #define MICROPY_PY_UBINASCII (1) #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) @@ -141,6 +143,7 @@ extern const struct _mp_obj_module_t mp_module_network; { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \ // extra constants #define MICROPY_PORT_CONSTANTS \ diff --git a/stmhal/mphalport.c b/stmhal/mphalport.c index 7a86989ffd..cea0369213 100644 --- a/stmhal/mphalport.c +++ b/stmhal/mphalport.c @@ -1,7 +1,7 @@ -#include <errno.h> #include <string.h> #include "py/mpstate.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "usb.h" #include "uart.h" @@ -9,9 +9,9 @@ // this table converts from HAL_StatusTypeDef to POSIX errno const byte mp_hal_status_to_errno_table[4] = { [HAL_OK] = 0, - [HAL_ERROR] = EIO, - [HAL_BUSY] = EBUSY, - [HAL_TIMEOUT] = ETIMEDOUT, + [HAL_ERROR] = MP_EIO, + [HAL_BUSY] = MP_EBUSY, + [HAL_TIMEOUT] = MP_ETIMEDOUT, }; NORETURN void mp_hal_raise(HAL_StatusTypeDef status) { diff --git a/stmhal/mphalport.h b/stmhal/mphalport.h index 7b29f9c9c0..b155d9616e 100644 --- a/stmhal/mphalport.h +++ b/stmhal/mphalport.h @@ -45,7 +45,7 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable #include "stmhal/pin.h" #define mp_hal_pin_obj_t pin_obj_t* #define mp_hal_get_pin_obj(o) (pin_obj_t*)pin_find(o) -#define mp_hal_pin_config_od(p) mp_hal_gpio_config((p)->gpio, (p)->pin, 5, 0, 0) -#define mp_hal_pin_low(p) GPIO_clear_pin((p)->gpio, (p)->pin_mask) +#define mp_hal_pin_open_drain(p) mp_hal_gpio_config((p)->gpio, (p)->pin, 5, 0, 0) +#define mp_hal_pin_od_low(p) GPIO_clear_pin((p)->gpio, (p)->pin_mask) #define mp_hal_pin_od_high(p) GPIO_set_pin((p)->gpio, (p)->pin_mask) #define mp_hal_pin_read(p) GPIO_read_pin((p)->gpio, (p)->pin) diff --git a/stmhal/pybstdio.c b/stmhal/pybstdio.c index 72c164b36d..352b7c10c2 100644 --- a/stmhal/pybstdio.c +++ b/stmhal/pybstdio.c @@ -26,10 +26,10 @@ #include <stdio.h> #include <string.h> -#include <errno.h> #include "py/obj.h" #include "py/stream.h" +#include "py/mperrno.h" #include "py/mphal.h" // TODO make stdin, stdout and stderr writable objects so they can @@ -69,7 +69,7 @@ STATIC mp_uint_t stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *er } return size; } else { - *errcode = EPERM; + *errcode = MP_EPERM; return MP_STREAM_ERROR; } } @@ -80,7 +80,7 @@ STATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, mp_hal_stdout_tx_strn_cooked(buf, size); return size; } else { - *errcode = EPERM; + *errcode = MP_EPERM; return MP_STREAM_ERROR; } } diff --git a/stmhal/sdcard.c b/stmhal/sdcard.c index 59fe3fac82..32c9df60a2 100644 --- a/stmhal/sdcard.c +++ b/stmhal/sdcard.c @@ -24,6 +24,8 @@ * THE SOFTWARE. */ +#include <string.h> + #include "py/nlr.h" #include "py/runtime.h" #include "lib/fatfs/ff.h" @@ -63,6 +65,11 @@ #define SDIO_TRANSFER_CLK_DIV SDMMC_TRANSFER_CLK_DIV +#elif defined(MCU_SERIES_L4) + +// The L4 series is not supported +#error Unsupported Processor + #endif // TODO: Since SDIO is fundamentally half-duplex, we really only need to @@ -77,22 +84,6 @@ static SD_HandleTypeDef sd_handle; static DMA_HandleTypeDef sd_rx_dma, sd_tx_dma; -// Parameters to dma_init() for SDIO tx and rx. -static const DMA_InitTypeDef dma_init_struct_sdio = { - .Channel = 0, - .Direction = 0, - .PeriphInc = DMA_PINC_DISABLE, - .MemInc = DMA_MINC_ENABLE, - .PeriphDataAlignment = DMA_PDATAALIGN_WORD, - .MemDataAlignment = DMA_MDATAALIGN_WORD, - .Mode = DMA_PFCTRL, - .Priority = DMA_PRIORITY_VERY_HIGH, - .FIFOMode = DMA_FIFOMODE_ENABLE, - .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL, - .MemBurst = DMA_MBURST_INC4, - .PeriphBurst = DMA_PBURST_INC4, -}; - void sdcard_init(void) { GPIO_InitTypeDef GPIO_Init_Structure; @@ -203,11 +194,6 @@ void SDIO_IRQHandler(void) { } mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { - // check that dest pointer is aligned on a 4-byte boundary - if (((uint32_t)dest & 3) != 0) { - return SD_ERROR; - } - // check that SD card is initialised if (sd_handle.Instance == NULL) { return SD_ERROR; @@ -215,12 +201,29 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo HAL_SD_ErrorTypedef err = SD_OK; + // check that dest pointer is aligned on a 4-byte boundary + uint8_t *orig_dest = NULL; + uint32_t saved_word; + if (((uint32_t)dest & 3) != 0) { + // Pointer is not aligned so it needs fixing. + // We could allocate a temporary block of RAM (as sdcard_write_blocks + // does) but instead we are going to use the dest buffer inplace. We + // are going to align the pointer, save the initial word at the aligned + // location, read into the aligned memory, move the memory back to the + // unaligned location, then restore the initial bytes at the aligned + // location. We should have no trouble doing this as those initial + // bytes at the aligned location should be able to be changed for the + // duration of this function call. + orig_dest = dest; + dest = (uint8_t*)((uint32_t)dest & ~3); + saved_word = *(uint32_t*)dest; + } + if (query_irq() == IRQ_STATE_ENABLED) { // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - dma_init(&sd_rx_dma, DMA_STREAM_SDIO_RX, &dma_init_struct_sdio, - DMA_CHANNEL_SDIO_RX, DMA_PERIPH_TO_MEMORY, &sd_handle); + dma_init(&sd_rx_dma, &dma_SDIO_0_RX, &sd_handle); sd_handle.hdmarx = &sd_rx_dma; err = HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); @@ -229,7 +232,7 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo err = HAL_SD_CheckReadOperation(&sd_handle, 100000000); } - dma_deinit(sd_handle.hdmarx); + dma_deinit(&dma_SDIO_0_RX); sd_handle.hdmarx = NULL; restore_irq_pri(basepri); @@ -237,15 +240,16 @@ mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blo err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks); } + if (orig_dest != NULL) { + // move the read data to the non-aligned position, and restore the initial bytes + memmove(orig_dest, dest, num_blocks * SDCARD_BLOCK_SIZE); + memcpy(dest, &saved_word, orig_dest - dest); + } + return err; } mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { - // check that src pointer is aligned on a 4-byte boundary - if (((uint32_t)src & 3) != 0) { - return SD_ERROR; - } - // check that SD card is initialised if (sd_handle.Instance == NULL) { return SD_ERROR; @@ -253,12 +257,29 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n HAL_SD_ErrorTypedef err = SD_OK; + // check that src pointer is aligned on a 4-byte boundary + if (((uint32_t)src & 3) != 0) { + // pointer is not aligned, so allocate a temporary block to do the write + uint8_t *src_aligned = m_new_maybe(uint8_t, SDCARD_BLOCK_SIZE); + if (src_aligned == NULL) { + return SD_ERROR; + } + for (size_t i = 0; i < num_blocks; ++i) { + memcpy(src_aligned, src + i * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE); + err = sdcard_write_blocks(src_aligned, block_num + i, 1); + if (err != SD_OK) { + break; + } + } + m_del(uint8_t, src_aligned, SDCARD_BLOCK_SIZE); + return err; + } + if (query_irq() == IRQ_STATE_ENABLED) { // we must disable USB irqs to prevent MSC contention with SD card uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - dma_init(&sd_tx_dma, DMA_STREAM_SDIO_TX, &dma_init_struct_sdio, - DMA_CHANNEL_SDIO_TX, DMA_MEMORY_TO_PERIPH, &sd_handle); + dma_init(&sd_tx_dma, &dma_SDIO_0_TX, &sd_handle); sd_handle.hdmatx = &sd_tx_dma; err = HAL_SD_WriteBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks); @@ -266,7 +287,7 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n // wait for DMA transfer to finish, with a large timeout err = HAL_SD_CheckWriteOperation(&sd_handle, 100000000); } - dma_deinit(sd_handle.hdmatx); + dma_deinit(&dma_SDIO_0_TX); sd_handle.hdmatx = NULL; restore_irq_pri(basepri); diff --git a/stmhal/spi.c b/stmhal/spi.c index 6285321a8b..387fc174c4 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -78,10 +78,8 @@ typedef struct _pyb_spi_obj_t { mp_obj_base_t base; SPI_HandleTypeDef *spi; - DMA_Stream_TypeDef *tx_dma_stream; - uint32_t tx_dma_channel; - DMA_Stream_TypeDef *rx_dma_stream; - uint32_t rx_dma_channel; + const dma_descr_t *tx_dma_descr; + const dma_descr_t *rx_dma_descr; } pyb_spi_obj_t; #if defined(MICROPY_HW_SPI1_SCK) @@ -105,34 +103,34 @@ SPI_HandleTypeDef SPIHandle6 = {.Instance = NULL}; STATIC const pyb_spi_obj_t pyb_spi_obj[] = { #if defined(MICROPY_HW_SPI1_SCK) - {{&pyb_spi_type}, &SPIHandle1, DMA_STREAM_SPI1_TX, DMA_CHANNEL_SPI1_TX, DMA_STREAM_SPI1_RX, DMA_CHANNEL_SPI1_RX}, + {{&pyb_spi_type}, &SPIHandle1, &dma_SPI_1_TX, &dma_SPI_1_RX}, #else - {{&pyb_spi_type}, NULL, NULL, 0, NULL, 0}, + {{&pyb_spi_type}, NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI2_SCK) - {{&pyb_spi_type}, &SPIHandle2, DMA_STREAM_SPI2_TX, DMA_CHANNEL_SPI2_TX, DMA_STREAM_SPI2_RX, DMA_CHANNEL_SPI2_RX}, + {{&pyb_spi_type}, &SPIHandle2, &dma_SPI_2_TX, &dma_SPI_2_RX}, #else - {{&pyb_spi_type}, NULL, NULL, 0, NULL, 0}, + {{&pyb_spi_type}, NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI3_SCK) - {{&pyb_spi_type}, &SPIHandle3, DMA_STREAM_SPI3_TX, DMA_CHANNEL_SPI3_TX, DMA_STREAM_SPI3_RX, DMA_CHANNEL_SPI3_RX}, + {{&pyb_spi_type}, &SPIHandle3, &dma_SPI_3_TX, &dma_SPI_3_RX}, #else - {{&pyb_spi_type}, NULL, NULL, 0, NULL, 0}, + {{&pyb_spi_type}, NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI4_SCK) - {{&pyb_spi_type}, &SPIHandle4, DMA_STREAM_SPI4_TX, DMA_CHANNEL_SPI4_TX, DMA_STREAM_SPI4_RX, DMA_CHANNEL_SPI4_RX}, + {{&pyb_spi_type}, &SPIHandle4, &dma_SPI_4_TX, &dma_SPI_4_RX}, #else - {{&pyb_spi_type}, NULL, NULL, 0, NULL, 0}, + {{&pyb_spi_type}, NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI5_SCK) - {{&pyb_spi_type}, &SPIHandle5, DMA_STREAM_SPI5_TX, DMA_CHANNEL_SPI5_TX, DMA_STREAM_SPI5_RX, DMA_CHANNEL_SPI5_RX}, + {{&pyb_spi_type}, &SPIHandle5, &dma_SPI_5_TX, &dma_SPI_5_RX}, #else - {{&pyb_spi_type}, NULL, NULL, 0, NULL, 0}, + {{&pyb_spi_type}, NULL, NULL, NULL}, #endif #if defined(MICROPY_HW_SPI6_SCK) - {{&pyb_spi_type}, &SPIHandle6, DMA_STREAM_SPI6_TX, DMA_CHANNEL_SPI6_TX, DMA_STREAM_SPI6_RX, DMA_CHANNEL_SPI6_RX}, + {{&pyb_spi_type}, &SPIHandle6, &dma_SPI_6_TX, &dma_SPI_6_RX}, #else - {{&pyb_spi_type}, NULL, NULL, 0, NULL, 0}, + {{&pyb_spi_type}, NULL, NULL, NULL}, #endif }; @@ -257,8 +255,8 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { // After calling HAL_SPI_Init() it seems that the DMA gets disconnected if // it was previously configured. So we invalidate the DMA channel to force // an initialisation the next time we use it. - dma_invalidate_channel(self->tx_dma_stream, self->tx_dma_channel); - dma_invalidate_channel(self->rx_dma_stream, self->rx_dma_channel); + dma_invalidate_channel(self->tx_dma_descr); + dma_invalidate_channel(self->rx_dma_descr); } void spi_deinit(SPI_HandleTypeDef *spi) { @@ -553,14 +551,14 @@ STATIC mp_obj_t pyb_spi_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, args[1].u_int); } else { DMA_HandleTypeDef tx_dma; - dma_init(&tx_dma, self->tx_dma_stream, &dma_init_struct_spi_i2c, self->tx_dma_channel, DMA_MEMORY_TO_PERIPH, self->spi); + dma_init(&tx_dma, self->tx_dma_descr, self->spi); self->spi->hdmatx = &tx_dma; self->spi->hdmarx = NULL; status = HAL_SPI_Transmit_DMA(self->spi, bufinfo.buf, bufinfo.len); if (status == HAL_OK) { status = spi_wait_dma_finished(self->spi, args[1].u_int); } - dma_deinit(&tx_dma); + dma_deinit(self->tx_dma_descr); } if (status != HAL_OK) { @@ -606,12 +604,12 @@ STATIC mp_obj_t pyb_spi_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ DMA_HandleTypeDef tx_dma, rx_dma; if (self->spi->Init.Mode == SPI_MODE_MASTER) { // in master mode the HAL actually does a TransmitReceive call - dma_init(&tx_dma, self->tx_dma_stream, &dma_init_struct_spi_i2c, self->tx_dma_channel, DMA_MEMORY_TO_PERIPH, self->spi); + dma_init(&tx_dma, self->tx_dma_descr, self->spi); self->spi->hdmatx = &tx_dma; } else { self->spi->hdmatx = NULL; } - dma_init(&rx_dma, self->rx_dma_stream, &dma_init_struct_spi_i2c, self->rx_dma_channel, DMA_PERIPH_TO_MEMORY, self->spi); + dma_init(&rx_dma, self->rx_dma_descr, self->spi); self->spi->hdmarx = &rx_dma; status = HAL_SPI_Receive_DMA(self->spi, (uint8_t*)vstr.buf, vstr.len); @@ -619,9 +617,9 @@ STATIC mp_obj_t pyb_spi_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ status = spi_wait_dma_finished(self->spi, args[1].u_int); } if (self->spi->hdmatx != NULL) { - dma_deinit(&tx_dma); + dma_deinit(self->tx_dma_descr); } - dma_deinit(&rx_dma); + dma_deinit(self->rx_dma_descr); } if (status != HAL_OK) { @@ -701,16 +699,16 @@ STATIC mp_obj_t pyb_spi_send_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp status = HAL_SPI_TransmitReceive(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len, args[2].u_int); } else { DMA_HandleTypeDef tx_dma, rx_dma; - dma_init(&tx_dma, self->tx_dma_stream, &dma_init_struct_spi_i2c, self->tx_dma_channel, DMA_MEMORY_TO_PERIPH, self->spi); + dma_init(&tx_dma, self->tx_dma_descr, self->spi); self->spi->hdmatx = &tx_dma; - dma_init(&rx_dma, self->rx_dma_stream, &dma_init_struct_spi_i2c, self->rx_dma_channel, DMA_PERIPH_TO_MEMORY, self->spi); + dma_init(&rx_dma, self->rx_dma_descr, self->spi); self->spi->hdmarx = &rx_dma; status = HAL_SPI_TransmitReceive_DMA(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len); if (status == HAL_OK) { status = spi_wait_dma_finished(self->spi, args[2].u_int); } - dma_deinit(&tx_dma); - dma_deinit(&rx_dma); + dma_deinit(self->tx_dma_descr); + dma_deinit(self->rx_dma_descr); } if (status != HAL_OK) { diff --git a/stmhal/startup_stm32.S b/stmhal/startup_stm32.S index 3c3783f7a0..25b0fdd392 100644 --- a/stmhal/startup_stm32.S +++ b/stmhal/startup_stm32.S @@ -44,10 +44,12 @@ */ .syntax unified -#if defined(MCU_SERIES_M7) +#if defined(MCU_SERIES_F7) .cpu cortex-m7 -#else +#elif defined(MCU_SERIES_F4) || defined(MCU_SERIES_L4) .cpu cortex-m4 +#else + #error "Unknown MCU Series" #endif .fpu softvfp .thumb @@ -164,7 +166,11 @@ 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 */ @@ -174,6 +180,16 @@ 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 */ @@ -182,14 +198,21 @@ 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 */ @@ -205,13 +228,24 @@ 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 */ -#if defined(MCU_SERIES_F7) +#endif +#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) .word FMC_IRQHandler /* FMC */ .word SDMMC1_IRQHandler /* SDMMC1 */ #else @@ -224,6 +258,19 @@ g_pfnVectors: .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 */ @@ -235,20 +282,40 @@ 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) @@ -307,8 +374,13 @@ 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 @@ -337,6 +409,31 @@ 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 @@ -360,6 +457,7 @@ g_pfnVectors: .weak ADC_IRQHandler .thumb_set ADC_IRQHandler,Default_Handler +#endif .weak CAN1_TX_IRQHandler .thumb_set CAN1_TX_IRQHandler,Default_Handler @@ -376,6 +474,16 @@ 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 @@ -384,6 +492,7 @@ 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 @@ -430,6 +539,19 @@ 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 @@ -441,14 +563,20 @@ 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) +#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) .weak FMC_IRQHandler .thumb_set FMC_IRQHandler,Default_Handler @@ -480,6 +608,40 @@ 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 @@ -512,10 +674,24 @@ 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 @@ -527,6 +703,7 @@ g_pfnVectors: .weak USART6_IRQHandler .thumb_set USART6_IRQHandler,Default_Handler +#endif .weak I2C3_EV_IRQHandler .thumb_set I2C3_EV_IRQHandler,Default_Handler @@ -534,6 +711,25 @@ 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 @@ -551,6 +747,7 @@ g_pfnVectors: .weak HASH_RNG_IRQHandler .thumb_set HASH_RNG_IRQHandler,Default_Handler +#endif .weak FPU_IRQHandler .thumb_set FPU_IRQHandler,Default_Handler diff --git a/stmhal/stm32_it.c b/stmhal/stm32_it.c index 4d3ffdffe2..c9af20ce58 100644 --- a/stmhal/stm32_it.c +++ b/stmhal/stm32_it.c @@ -477,6 +477,14 @@ void PVD_IRQHandler(void) { IRQ_EXIT(PVD_IRQn); } +#if defined(MCU_SERIES_L4) +void PVD_PVM_IRQHandler(void) { + IRQ_ENTER(PVD_PVM_IRQn); + Handle_EXTI_Irq(EXTI_PVD_OUTPUT); + IRQ_EXIT(PVD_PVM_IRQn); +} +#endif + void RTC_Alarm_IRQHandler(void) { IRQ_ENTER(RTC_Alarm_IRQn); Handle_EXTI_Irq(EXTI_RTC_ALARM); @@ -510,6 +518,14 @@ void TIM1_BRK_TIM9_IRQHandler(void) { IRQ_EXIT(TIM1_BRK_TIM9_IRQn); } +#if defined(MCU_SERIES_L4) +void TIM1_BRK_TIM15_IRQHandler(void) { + IRQ_ENTER(TIM1_BRK_TIM15_IRQn); + timer_irq_handler(15); + IRQ_EXIT(TIM1_BRK_TIM15_IRQn); +} +#endif + void TIM1_UP_TIM10_IRQHandler(void) { IRQ_ENTER(TIM1_UP_TIM10_IRQn); timer_irq_handler(1); @@ -517,12 +533,29 @@ void TIM1_UP_TIM10_IRQHandler(void) { IRQ_EXIT(TIM1_UP_TIM10_IRQn); } +#if defined(MCU_SERIES_L4) +void TIM1_UP_TIM16_IRQHandler(void) { + IRQ_ENTER(TIM1_UP_TIM16_IRQn); + timer_irq_handler(1); + timer_irq_handler(16); + IRQ_EXIT(TIM1_UP_TIM16_IRQn); +} +#endif + void TIM1_TRG_COM_TIM11_IRQHandler(void) { IRQ_ENTER(TIM1_TRG_COM_TIM11_IRQn); timer_irq_handler(11); IRQ_EXIT(TIM1_TRG_COM_TIM11_IRQn); } +#if defined(MCU_SERIES_L4) +void TIM1_TRG_COM_TIM17_IRQHandler(void) { + IRQ_ENTER(TIM1_TRG_COM_TIM17_IRQn); + timer_irq_handler(17); + IRQ_EXIT(TIM1_TRG_COM_TIM17_IRQn); +} +#endif + void TIM2_IRQHandler(void) { IRQ_ENTER(TIM2_IRQn); timer_irq_handler(2); @@ -573,6 +606,14 @@ void TIM8_UP_TIM13_IRQHandler(void) { IRQ_EXIT(TIM8_UP_TIM13_IRQn); } +#if defined(MCU_SERIES_L4) +void TIM8_UP_IRQHandler(void) { + IRQ_ENTER(TIM8_UP_IRQn); + timer_irq_handler(8); + IRQ_EXIT(TIM8_UP_IRQn); +} +#endif + void TIM8_TRG_COM_TIM14_IRQHandler(void) { IRQ_ENTER(TIM8_TRG_COM_TIM14_IRQn); timer_irq_handler(14); diff --git a/stmhal/system_stm32.c b/stmhal/system_stm32.c index e286a15725..96caa7d36d 100644 --- a/stmhal/system_stm32.c +++ b/stmhal/system_stm32.c @@ -108,6 +108,30 @@ void __fatal_error(const char *msg); * @{ */ +#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + +#define CONFIG_RCC_CR_1ST (RCC_CR_HSION) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON) +#define CONFIG_RCC_PLLCFGR (0x24003010) + +#elif defined(MCU_SERIES_L4) + +#define CONFIG_RCC_CR_1ST (RCC_CR_MSION) +#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_HSION || RCC_CR_PLLON) +#define CONFIG_RCC_PLLCFGR (0x00001000) +/* + * FIXME Do not know why I have to define these arrays here! they should be defined in the + * hal_rcc-file!! + * + */ +const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; +const uint32_t MSIRangeTable[12] = {100000, 200000, 400000, 800000, 1000000, 2000000, \ + 4000000, 8000000, 16000000, 24000000, 32000000, 48000000}; +#else +#error Unknown processor +#endif + /************************* Miscellaneous Configuration ************************/ /*!< Uncomment the following line if you need to relocate your vector Table in @@ -172,23 +196,28 @@ void SystemInit(void) SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ #endif /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set HSION bit */ - RCC->CR |= (uint32_t)0x00000001; + RCC->CR |= CONFIG_RCC_CR_1ST; /* Reset CFGR register */ RCC->CFGR = 0x00000000; /* Reset HSEON, CSSON and PLLON bits */ - RCC->CR &= (uint32_t)0xFEF6FFFF; + RCC->CR &= ~ CONFIG_RCC_CR_2ND; /* Reset PLLCFGR register */ - RCC->PLLCFGR = 0x24003010; + RCC->PLLCFGR = CONFIG_RCC_PLLCFGR; /* Reset HSEBYP bit */ RCC->CR &= (uint32_t)0xFFFBFFFF; /* Disable all interrupts */ + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) RCC->CIR = 0x00000000; + #elif defined(MCU_SERIES_L4) + RCC->CIER = 0x00000000; + #endif /* Configure the Vector Table location add offset address ------------------*/ #ifdef VECT_TAB_SRAM @@ -204,7 +233,8 @@ void SystemInit(void) /** * @brief System Clock Configuration - * The system Clock is configured as follow : + * + * The system Clock is configured for F4/F7 as follows: * System Clock source = PLL (HSE) * SYSCLK(Hz) = 168000000 * HCLK(Hz) = 168000000 @@ -219,15 +249,39 @@ void SystemInit(void) * VDD(V) = 3.3 * Main regulator output voltage = Scale1 mode * Flash Latency(WS) = 5 + * + * The system Clock is configured for L4 as follows: + * System Clock source = PLL (MSI) + * SYSCLK(Hz) = 80000000 + * HCLK(Hz) = 80000000 + * AHB Prescaler = 1 + * APB1 Prescaler = 1 + * APB2 Prescaler = 1 + * MSI Frequency(Hz) = MSI_VALUE (4000000) + * LSE Frequency(Hz) = 32768 + * PLL_M = 1 + * PLL_N = 40 + * PLL_P = 7 + * PLL_Q = 2 + * PLL_R = 2 <= This is the source for SysClk, not as on F4/7 PLL_P + * Flash Latency(WS) = 4 * @param None * @retval None * * PLL is configured as follows: * - * VCO_IN = HSE / M - * VCO_OUT = HSE / M * N - * PLLCLK = HSE / M * N / P - * PLL48CK = HSE / M * N / Q + * VCO_IN + * F4/F7 = HSE / M + * L4 = MSI / M + * VCO_OUT + * F4/F7 = HSE / M * N + * L4 = MSI / M * N + * PLLCLK + * F4/F7 = HSE / M * N / P + * L4 = MSI / M * N / R + * PLL48CK + * F4/F7 = HSE / M * N / Q + * L4 = MSI / M * N / Q USB Clock is obtained over PLLSAI1 * * SYSCLK = PLLCLK * HCLK = SYSCLK / AHB_PRESC @@ -261,6 +315,7 @@ void SystemClock_Config(void) RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitTypeDef RCC_OscInitStruct; + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) /* Enable Power Control clock */ __PWR_CLK_ENABLE(); @@ -268,12 +323,29 @@ void SystemClock_Config(void) clocked below the maximum system frequency, to update the voltage scaling value regarding system frequency refer to product datasheet. */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + #elif defined(MCU_SERIES_L4) + /* Enable the LSE Oscillator */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; + RCC_OscInitStruct.LSEState = RCC_LSE_ON; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + __fatal_error("HAL_RCC_OscConfig"); + } + #endif /* Enable HSE Oscillator and activate PLL with HSE as source */ + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + #elif defined(MCU_SERIES_L4) + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; + RCC_OscInitStruct.LSEState = RCC_LSE_ON; + RCC_OscInitStruct.MSIState = RCC_MSI_ON; + RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; + RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI; + #endif + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; /* 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); @@ -282,6 +354,8 @@ void SystemClock_Config(void) #if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ #if defined(MCU_SERIES_F7) #define FREQ_BKP BKP31R + #elif defined(MCU_SERIES_L4) + #error Unsupported Processor #else #define FREQ_BKP BKP19R #endif @@ -319,15 +393,23 @@ void SystemClock_Config(void) RCC_ClkInitStruct.AHBCLKDivider = h; //RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = b1; //RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = b2; //RCC_HCLK_DIV2; -#else +#else // defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ RCC_OscInitStruct.PLL.PLLM = MICROPY_HW_CLK_PLLM; RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; RCC_OscInitStruct.PLL.PLLP = MICROPY_HW_CLK_PLLP; RCC_OscInitStruct.PLL.PLLQ = MICROPY_HW_CLK_PLLQ; + #if defined(MCU_SERIES_L4) + RCC_OscInitStruct.PLL.PLLR = MICROPY_HW_CLK_PLLR; + #endif RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + #elif defined(MCU_SERIES_L4) + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + #endif #endif if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { @@ -358,6 +440,44 @@ void SystemClock_Config(void) RCC->DCKCFGR2 = 0; #endif +#if defined(MCU_SERIES_L4) + // Enable MSI-Hardware auto calibration mode with LSE + HAL_RCCEx_EnableMSIPLLMode(); + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1|RCC_PERIPHCLK_I2C1 + |RCC_PERIPHCLK_USB |RCC_PERIPHCLK_ADC + |RCC_PERIPHCLK_RNG |RCC_PERIPHCLK_RTC; + PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; + /* PLLSAI is used to clock USB, ADC, I2C1 and RNG. The frequency is + HSE(8MHz)/PLLM(2)*PLLSAI1N(24)/PLLSAIQ(2) = 48MHz. See the STM32CubeMx + application or the reference manual. */ + PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; + PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1; + PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1; + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; + PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_PLLSAI1; + PeriphClkInitStruct.PLLSAI1.PLLSAI1N = 24; + PeriphClkInitStruct.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7; + PeriphClkInitStruct.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2; + PeriphClkInitStruct.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2; + PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK + |RCC_PLLSAI1_48M2CLK + |RCC_PLLSAI1_ADC1CLK; + + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) + { + __fatal_error("HAL_RCCEx_PeriphCLKConfig"); + } + + __PWR_CLK_ENABLE(); + + HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); + + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); +#endif } void HAL_MspInit(void) { diff --git a/stmhal/uart.c b/stmhal/uart.c index 108236ca1a..210330e81a 100644 --- a/stmhal/uart.c +++ b/stmhal/uart.c @@ -27,11 +27,11 @@ #include <stdio.h> #include <string.h> #include <stdarg.h> -#include <errno.h> #include "py/nlr.h" #include "py/runtime.h" #include "py/stream.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "uart.h" #include "pybioctl.h" @@ -579,11 +579,7 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, mp_uint_t n_args, con } else { actual_baudrate = HAL_RCC_GetPCLK1Freq(); } - #if defined(MCU_SERIES_L4) - actual_baudrate = (actual_baudrate << 5) / (self->uart.Instance->BRR >> 3); - #else actual_baudrate /= self->uart.Instance->BRR; - #endif // check we could set the baudrate within 5% uint32_t baudrate_diff; @@ -829,7 +825,7 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i // check that size is a multiple of character width if (size & self->char_width) { - *errcode = EIO; + *errcode = MP_EIO; return MP_STREAM_ERROR; } @@ -844,7 +840,7 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i // wait for first char to become available if (!uart_rx_wait(self, self->timeout)) { // return EAGAIN error to indicate non-blocking (then read() method returns None) - *errcode = EAGAIN; + *errcode = MP_EAGAIN; return MP_STREAM_ERROR; } @@ -871,13 +867,13 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t // check that size is a multiple of character width if (size & self->char_width) { - *errcode = EIO; + *errcode = MP_EIO; return MP_STREAM_ERROR; } // wait to be able to write the first character. EAGAIN causes write to return None if (!uart_tx_wait(self, self->timeout)) { - *errcode = EAGAIN; + *errcode = MP_EAGAIN; return MP_STREAM_ERROR; } @@ -917,7 +913,7 @@ STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t a ret |= MP_IOCTL_POLL_WR; } } else { - *errcode = EINVAL; + *errcode = MP_EINVAL; ret = MP_STREAM_ERROR; } return ret; diff --git a/stmhal/usb.c b/stmhal/usb.c index 1e1469c564..b786fb7584 100644 --- a/stmhal/usb.c +++ b/stmhal/usb.c @@ -26,7 +26,6 @@ #include <stdarg.h> #include <string.h> -#include <errno.h> #include "usbd_core.h" #include "usbd_desc.h" @@ -37,6 +36,7 @@ #include "py/objstr.h" #include "py/runtime.h" #include "py/stream.h" +#include "py/mperrno.h" #include "bufhelper.h" #include "usb.h" #include "pybioctl.h" @@ -483,7 +483,7 @@ STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, i int ret = USBD_CDC_Rx((byte*)buf, size, 0); if (ret == 0) { // return EAGAIN error to indicate non-blocking - *errcode = EAGAIN; + *errcode = MP_EAGAIN; return MP_STREAM_ERROR; } return ret; @@ -493,7 +493,7 @@ STATIC mp_uint_t pyb_usb_vcp_write(mp_obj_t self_in, const void *buf, mp_uint_t int ret = USBD_CDC_Tx((const byte*)buf, size, 0); if (ret == 0) { // return EAGAIN error to indicate non-blocking - *errcode = EAGAIN; + *errcode = MP_EAGAIN; return MP_STREAM_ERROR; } return ret; @@ -511,7 +511,7 @@ STATIC mp_uint_t pyb_usb_vcp_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_ ret |= MP_IOCTL_POLL_WR; } } else { - *errcode = EINVAL; + *errcode = MP_EINVAL; ret = MP_STREAM_ERROR; } return ret; @@ -600,7 +600,7 @@ STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_ ret |= MP_IOCTL_POLL_WR; } } else { - *errcode = EINVAL; + *errcode = MP_EINVAL; ret = MP_STREAM_ERROR; } return ret; diff --git a/tests/basics/fun_calldblstar3.py b/tests/basics/fun_calldblstar3.py new file mode 100644 index 0000000000..4367e68df7 --- /dev/null +++ b/tests/basics/fun_calldblstar3.py @@ -0,0 +1,16 @@ +# test passing a user-defined mapping as the argument to ** + +def foo(**kw): + print(sorted(kw.items())) + +class Mapping: + def keys(self): + return ['a', 'b', 'c'] + + def __getitem__(self, key): + if key == 'a': + return 1 + else: + return 2 + +foo(**Mapping()) diff --git a/tests/basics/int_big_div.py b/tests/basics/int_big_div.py index 8dacf495db..642f051d41 100644 --- a/tests/basics/int_big_div.py +++ b/tests/basics/int_big_div.py @@ -1,3 +1,10 @@ for lhs in (1000000000000000000000000, 10000000000100000000000000, 10012003400000000000000007, 12349083434598210349871029923874109871234789): for rhs in range(1, 555): print(lhs // rhs) + +# these check an edge case on 64-bit machines where two mpz limbs +# are used and the most significant one has the MSB set +x = 0x8000000000000000 +print((x + 1) // x) +x = 0x86c60128feff5330 +print((x + 1) // x) diff --git a/tests/basics/int_big_mod.py b/tests/basics/int_big_mod.py index 77c0ffc468..e87221c1c7 100644 --- a/tests/basics/int_big_mod.py +++ b/tests/basics/int_big_mod.py @@ -4,7 +4,14 @@ delta = 100000000000000000000000000000012345 for i in range(11): for j in range(11): - x = delta * (i)# - 5) # TODO reinstate negative number test when % is working with sign correctly - y = delta * (j)# - 5) # TODO reinstate negative number test when % is working with sign correctly + x = delta * (i - 5) + y = delta * (j - 5) if y != 0: print(x % y) + +# these check an edge case on 64-bit machines where two mpz limbs +# are used and the most significant one has the MSB set +x = 0x8000000000000000 +print((x + 1) % x) +x = 0x86c60128feff5330 +print((x + 1) % x) diff --git a/tests/basics/memoryview2.py b/tests/basics/memoryview2.py new file mode 100644 index 0000000000..5117d7a680 --- /dev/null +++ b/tests/basics/memoryview2.py @@ -0,0 +1,13 @@ +# test memoryview accessing maximum values for signed/unsigned elements + +from array import array + +print(list(memoryview(b'\x7f\x80\x81\xff'))) +print(list(memoryview(array('b', [0x7f, -0x80])))) +print(list(memoryview(array('B', [0x7f, 0x80, 0x81, 0xff])))) +print(list(memoryview(array('h', [0x7f00, -0x8000])))) +print(list(memoryview(array('H', [0x7f00, 0x8000, 0x8100, 0xffff])))) + +# these constructors give an internal overflow in uPy +#print(list(memoryview(array('i', [0x7f000000, -0x80000000])))) +#print(list(memoryview(array('I', [0x7f000000, 0x80000000, 0x81000000, 0xffffffff])))) diff --git a/tests/basics/namedtuple1.py b/tests/basics/namedtuple1.py index dfbb79f2eb..346e32fbfc 100644 --- a/tests/basics/namedtuple1.py +++ b/tests/basics/namedtuple1.py @@ -66,6 +66,11 @@ T3 = namedtuple("TupComma", "foo bar") t = T3(1, 2) print(t.foo, t.bar) +# Try tuple +T4 = namedtuple("TupTuple", ("foo", "bar")) +t = T4(1, 2) +print(t.foo, t.bar) + # Try single string with comma field seperator # Not implemented so far #T2 = namedtuple("TupComma", "foo,bar") diff --git a/tests/basics/string_center.py b/tests/basics/string_center.py new file mode 100644 index 0000000000..a2739201ac --- /dev/null +++ b/tests/basics/string_center.py @@ -0,0 +1,14 @@ +try: + str.center +except: + import sys + print("SKIP") + sys.exit() + +print("foo".center(0)) +print("foo".center(1)) +print("foo".center(3)) +print("foo".center(4)) +print("foo".center(5)) +print("foo".center(6)) +print("foo".center(20)) diff --git a/tests/basics/string_splitlines.py b/tests/basics/string_splitlines.py index cb4dacef9f..1d08f6e6d7 100644 --- a/tests/basics/string_splitlines.py +++ b/tests/basics/string_splitlines.py @@ -1,3 +1,5 @@ +# test string.splitlines() method + try: str.splitlines except: @@ -5,9 +7,32 @@ except: print("SKIP") sys.exit() +# test \n as newline print("foo\nbar".splitlines()) print("foo\nbar\n".splitlines()) +print("foo and\nbar\n".splitlines()) +print("foo\nbar\n\n".splitlines()) +print("foo\n\nbar\n\n".splitlines()) +print("\nfoo\nbar\n".splitlines()) + +# test \r as newline +print("foo\rbar\r".splitlines()) +print("\rfoo and\r\rbar\r".splitlines()) + +# test \r\n as newline +print("foo\r\nbar\r\n".splitlines()) +print("\r\nfoo and\r\n\r\nbar\r\n".splitlines()) + +# test keepends arg print("foo\nbar".splitlines(True)) print("foo\nbar\n".splitlines(True)) -print("foo\nbar".splitlines(keepends=True)) -print("foo\nbar\n".splitlines(keepends=True)) +print("foo\nbar\n\n".splitlines(True)) +print("foo\rbar".splitlines(keepends=True)) +print("foo\rbar\r\r".splitlines(keepends=True)) +print("foo\r\nbar".splitlines(keepends=True)) +print("foo\r\nbar\r\n\r\n".splitlines(keepends=True)) + +# test splitting bytes objects +print(b"foo\nbar".splitlines()) +print(b"foo\nbar\n".splitlines()) +print(b"foo\r\nbar\r\n\r\n".splitlines(True)) diff --git a/tests/basics/struct1.py b/tests/basics/struct1.py index 1afea5a96f..857e171c10 100644 --- a/tests/basics/struct1.py +++ b/tests/basics/struct1.py @@ -62,6 +62,12 @@ try: except TypeError: print('TypeError') +# make sure that unknown types are detected +try: + struct.pack("z", 1) +except: + print("Unknown type") + # Initially repitition counters were supported only for strings, # but later were implemented for all. print(struct.unpack("<3B2h", b"foo\x12\x34\xff\xff")) diff --git a/tests/basics/struct2.py b/tests/basics/struct2.py new file mode 100644 index 0000000000..f438bb55d2 --- /dev/null +++ b/tests/basics/struct2.py @@ -0,0 +1,28 @@ +# test ustruct with a count specified before the type + +try: + import ustruct as struct +except: + import struct + +print(struct.calcsize('0s')) +print(struct.unpack('0s', b'')) +print(struct.pack('0s', b'123')) + +print(struct.calcsize('2s')) +print(struct.unpack('2s', b'12')) +print(struct.pack('2s', b'123')) + +print(struct.calcsize('2H')) +print(struct.unpack('<2H', b'1234')) +print(struct.pack('<2H', 258, 515)) + +print(struct.calcsize('0s1s0H2H')) +print(struct.unpack('<0s1s0H2H', b'01234')) +print(struct.pack('<0s1s0H2H', b'abc', b'abc', 258, 515)) + +# check that zero of an unknown type raises an exception +try: + struct.calcsize('0z') +except: + print('Exception') diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index 72eda8b6d0..7860d68124 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -45,6 +45,8 @@ assert b"hello!" not in bdev.data vfs = uos.VfsFat(bdev, "/ramdisk") +print("getcwd:", vfs.getcwd()) + f = vfs.open("foo_file.txt", "w") f.write("hello!") f.close() @@ -71,3 +73,14 @@ assert vfs.listdir("foo_dir") == ['file-in-dir.txt'] vfs.rename("foo_dir/file-in-dir.txt", "moved-to-root.txt") assert vfs.listdir() == ['foo_dir', 'moved-to-root.txt'] + +vfs.chdir("foo_dir") +print("getcwd:", vfs.getcwd()) +assert vfs.listdir() == [] + +with vfs.open("sub_file.txt", "w") as f: + f.write("test2") +assert vfs.listdir() == ["sub_file.txt"] + +vfs.chdir("..") +print("getcwd:", vfs.getcwd()) diff --git a/tests/extmod/vfs_fat_ramdisk.py.exp b/tests/extmod/vfs_fat_ramdisk.py.exp index 4effa19f4f..b6079ad3b6 100644 --- a/tests/extmod/vfs_fat_ramdisk.py.exp +++ b/tests/extmod/vfs_fat_ramdisk.py.exp @@ -1 +1,4 @@ +getcwd: /ramdisk hello! +getcwd: /ramdisk/foo_dir +getcwd: /ramdisk diff --git a/tests/misc/recursive_iternext.py b/tests/misc/recursive_iternext.py index 2723d3c10c..376c45b3c7 100644 --- a/tests/misc/recursive_iternext.py +++ b/tests/misc/recursive_iternext.py @@ -1,10 +1,19 @@ # This tests that recursion with iternext doesn't lead to segfault. +# We need to pick an N that is large enough to hit the recursion +# limit, but not too large that we run out of heap memory. try: - [0] * 10000 - N = 1000 + # large stack/heap, eg unix + [0] * 80000 + N = 2000 except: - N = 100 + try: + # medium, eg pyboard + [0] * 10000 + N = 1000 + except: + # small, eg esp8266 + N = 100 try: x = (1, 2) diff --git a/tests/pyb/can.py b/tests/pyb/can.py index cf8089a3bd..594d1d5093 100644 --- a/tests/pyb/can.py +++ b/tests/pyb/can.py @@ -8,6 +8,7 @@ for bus in (-1, 0, 1, 2, 3, "YA", "YB", "YC"): print("CAN", bus) except ValueError: print("ValueError", bus) +CAN(1).deinit() CAN.initfilterbanks(14) can = CAN(1) diff --git a/tests/pyb/halerror.py.exp b/tests/pyb/halerror.py.exp index 09c9f7ad92..0f3f26253d 100644 --- a/tests/pyb/halerror.py.exp +++ b/tests/pyb/halerror.py.exp @@ -1,2 +1,2 @@ OSError(5,) -OSError(116,) +OSError(110,) diff --git a/tests/pyb/rtc.py b/tests/pyb/rtc.py index 09af52629f..300c956342 100644 --- a/tests/pyb/rtc.py +++ b/tests/pyb/rtc.py @@ -2,6 +2,7 @@ import pyb, stm from pyb import RTC rtc = RTC() +rtc.init() print(rtc) # make sure that 1 second passes correctly diff --git a/tests/run-tests b/tests/run-tests index fd4063dc91..649f1789fa 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -351,14 +351,15 @@ def main(): cmd_parser.add_argument('files', nargs='*', help='input test files') args = cmd_parser.parse_args() - if args.target in ('pyboard', 'wipy', 'esp8266'): + EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266') + if args.target in EXTERNAL_TARGETS: import pyboard pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password) pyb.enter_raw_repl() elif args.target == 'unix': pyb = None else: - raise ValueError('target must be either unix, pyboard or wipy') + raise ValueError('target must be either %s or unix' % ", ".join(EXTERNAL_TARGETS)) if len(args.files) == 0: if args.test_dirs is None: diff --git a/tools/make-frozen.py b/tools/make-frozen.py index 84e589b985..1051b520e4 100755 --- a/tools/make-frozen.py +++ b/tools/make-frozen.py @@ -23,7 +23,7 @@ import os def module_name(f): - return f[:-len(".py")] + return f modules = [] @@ -53,11 +53,31 @@ print("};") print("const char mp_frozen_str_content[] = {") for f, st in modules: data = open(sys.argv[1] + "/" + f, "rb").read() - # Python2 vs Python3 tricks - data = repr(data) - if data[0] == "b": - data = data[1:] - data = data[1:-1] - data = data.replace('"', '\\"') - print('"%s\\0"' % data) + + # We need to properly escape the script data to create a C string. + # When C parses hex characters of the form \x00 it keeps parsing the hex + # data until it encounters a non-hex character. Thus one must create + # strings of the form "data\x01" "abc" to properly encode this kind of + # data. We could just encode all characters as hex digits but it's nice + # to be able to read the resulting C code as ASCII when possible. + + data = bytearray(data) # so Python2 extracts each byte as an integer + esc_dict = {ord('\n'): '\\n', ord('\r'): '\\r', ord('"'): '\\"', ord('\\'): '\\\\'} + chrs = ['"'] + break_str = False + for c in data: + try: + chrs.append(esc_dict[c]) + except KeyError: + if 32 <= c <= 126: + if break_str: + chrs.append('" "') + break_str = False + chrs.append(chr(c)) + else: + chrs.append('\\x%02x' % c) + break_str = True + chrs.append('\\0"') + print(''.join(chrs)) + print("};") diff --git a/tools/micropython-upip-0.6.3.tar.gz b/tools/micropython-upip-0.6.3.tar.gz Binary files differdeleted file mode 100644 index 00ce80642d..0000000000 --- a/tools/micropython-upip-0.6.3.tar.gz +++ /dev/null diff --git a/tools/micropython-upip-0.7.tar.gz b/tools/micropython-upip-0.7.tar.gz Binary files differnew file mode 100644 index 0000000000..cd36d136e2 --- /dev/null +++ b/tools/micropython-upip-0.7.tar.gz diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 74106f192a..972ede8325 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -450,6 +450,23 @@ def freeze_mpy(qcfgs, base_qstrs, raw_codes): print('#include "py/emitglue.h"') print() + print('#if MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE') + print('#error "MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE not supported with frozen mpy files"') + print('#endif') + print() + + print('#if MICROPY_LONGINT_IMPL != %u' % config.MICROPY_LONGINT_IMPL) + print('#error "incompatible MICROPY_LONGINT_IMPL"') + print('#endif') + print() + + if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ: + print('#if MPZ_DIG_SIZE != %u' % config.MPZ_DIG_SIZE) + print('#error "incompatible MPZ_DIG_SIZE"') + print('#endif') + print() + + print('#if MICROPY_PY_BUILTINS_FLOAT') print('typedef struct _mp_obj_float_t {') print(' mp_obj_base_t base;') @@ -485,10 +502,7 @@ def freeze_mpy(qcfgs, base_qstrs, raw_codes): print() print('const char mp_frozen_mpy_names[] = {') for rc in raw_codes: - module_name = rc.source_file.str[:-len(".py")] - slash = module_name.rfind('/') - if slash != -1: - module_name = module_name[slash + 1:] + module_name = rc.source_file.str print('"%s\\0"' % module_name) print('"\\0"};') diff --git a/unix/Makefile b/unix/Makefile index 655f26bb93..90653e88e8 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -15,6 +15,7 @@ include ../py/py.mk INC += -I. INC += -I.. +INC += -I../lib/timeutils INC += -I$(BUILD) # compiler settings @@ -163,6 +164,7 @@ LIB_SRC_C = $(addprefix lib/,\ utils/printf.c \ fatfs/ff.c \ fatfs/option/ccsbcs.c \ + timeutils/timeutils.c \ ) OBJ = $(PY_O) @@ -176,6 +178,31 @@ SRC_QSTR += $(SRC_C) $(LIB_SRC_C) # SRC_QSTR SRC_QSTR_AUTO_DEPS += +ifneq ($(FROZEN_MPY_DIR),) +# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and +# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). +MPY_CROSS = ../mpy-cross/mpy-cross +MPY_TOOL = ../tools/mpy-tool.py +FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py') +FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) +CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool +CFLAGS += -DMICROPY_MODULE_FROZEN_MPY +CFLAGS += -DMICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE=0 # not supported +CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs +OBJ += $(BUILD)/$(BUILD)/frozen_mpy.o + +# to build .mpy files from .py files +$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py + @$(ECHO) "MPY $<" + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ + +# to build frozen_mpy.c from all .mpy files +$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h + @$(ECHO) "Creating $@" + $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ +endif + include ../py/mkrules.mk @@ -217,6 +244,7 @@ nanbox: BUILD=build-nanbox \ PROG=micropython_nanbox \ MICROPY_FORCE_32BIT=1 \ + MICROPY_PY_USSL=0 freedos: $(MAKE) \ @@ -232,7 +260,7 @@ freedos: # build an interpreter for coverage testing and do the testing coverage: - $(MAKE) COPT="-O0" CFLAGS_EXTRA='-fprofile-arcs -ftest-coverage -Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wold-style-definition -Wpointer-arith -Wshadow -Wsign-compare -Wuninitialized -Wunused-parameter -DMICROPY_UNIX_COVERAGE -DMICROPY_PY_URANDOM_EXTRA_FUNCS' LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' BUILD=build-coverage PROG=micropython_coverage + $(MAKE) COPT="-O0" CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_coverage.h>" -fprofile-arcs -ftest-coverage -Wdouble-promotion -Wformat -Wmissing-declarations -Wmissing-prototypes -Wold-style-definition -Wpointer-arith -Wshadow -Wsign-compare -Wuninitialized -Wunused-parameter -DMICROPY_UNIX_COVERAGE' LDFLAGS_EXTRA='-fprofile-arcs -ftest-coverage' BUILD=build-coverage PROG=micropython_coverage coverage_test: coverage $(eval DIRNAME=$(notdir $(CURDIR))) @@ -276,8 +304,12 @@ libffi: ../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \ make install-exec-recursive; make -C include install-data-am -axtls: +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)" + +../lib/axtls/README: + @echo "You cloned without --recursive, fetching submodules for you." + (cd ..; git submodule update --init --recursive) diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index abda432580..9601673a74 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -64,11 +64,14 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_STREAMS_NON_BLOCK (1) #define MICROPY_OPT_COMPUTED_GOTO (1) +#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE #define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (1) +#endif #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_PY_FUNCTION_ATTRS (1) #define MICROPY_PY_DESCRIPTORS (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) #define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) #define MICROPY_PY_BUILTINS_FROZENSET (1) @@ -100,6 +103,7 @@ #define MICROPY_STACKLESS_STRICT (0) #define MICROPY_PY_OS_STATVFS (1) +#define MICROPY_PY_UERRNO (1) #define MICROPY_PY_UCTYPES (1) #define MICROPY_PY_UZLIB (1) #define MICROPY_PY_UJSON (1) diff --git a/unix/mpconfigport.mk b/unix/mpconfigport.mk index 1b2b5231bc..88bd749a71 100644 --- a/unix/mpconfigport.mk +++ b/unix/mpconfigport.mk @@ -22,7 +22,11 @@ MICROPY_PY_SOCKET = 1 MICROPY_PY_FFI = 1 # ussl module requires axtls -MICROPY_PY_USSL = 0 +MICROPY_PY_USSL = 1 # jni module requires JVM/JNI MICROPY_PY_JNI = 0 + +# Avoid using system libraries, use copies bundled with MicroPython +# as submodules (currently affects only libffi). +MICROPY_STANDALONE = 0 diff --git a/unix/mpconfigport_coverage.h b/unix/mpconfigport_coverage.h new file mode 100644 index 0000000000..e5d5fd7a47 --- /dev/null +++ b/unix/mpconfigport_coverage.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Default unix config while intended to be comprehensive, may still not enable +// all the features, this config should enable more (testable) options. + +#include <mpconfigport.h> + +#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_IO_BUFFEREDWRITER (1) diff --git a/unix/mphalport.h b/unix/mphalport.h index 57baf07d42..2a775d9828 100644 --- a/unix/mphalport.h +++ b/unix/mphalport.h @@ -35,6 +35,7 @@ void mp_hal_stdio_mode_raw(void); void mp_hal_stdio_mode_orig(void); static inline void mp_hal_delay_ms(mp_uint_t ms) { usleep((ms) * 1000); } +static inline void mp_hal_delay_us(mp_uint_t us) { usleep(us); } #define RAISE_ERRNO(err_flag, error_val) \ { if (err_flag == -1) \ diff --git a/unix/unix_mphal.c b/unix/unix_mphal.c index df37976272..6c66662362 100644 --- a/unix/unix_mphal.c +++ b/unix/unix_mphal.c @@ -191,3 +191,9 @@ mp_uint_t mp_hal_ticks_ms(void) { gettimeofday(&tv, NULL); return tv.tv_sec * 1000 + tv.tv_usec / 1000; } + +mp_uint_t mp_hal_ticks_us(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +} diff --git a/windows/msvc/common.props b/windows/msvc/common.props index cfb6adbc14..26ea78e7e5 100644 --- a/windows/msvc/common.props +++ b/windows/msvc/common.props @@ -16,6 +16,8 @@ <SDLCheck>false</SDLCheck> <WarningLevel>Level1</WarningLevel> <ExceptionHandling>false</ExceptionHandling> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <MinimalRebuild>false</MinimalRebuild> </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> |