From ad5a6f591796c2dec6e91e9da147eaa7e9ee72a7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 4 Nov 2017 00:26:31 +0200 Subject: docs/ure: Add flags arg to ure.compile(), mention that ure.DEBUG is optional. --- docs/library/ure.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'docs/library') diff --git a/docs/library/ure.rst b/docs/library/ure.rst index ebae1db5f..9a5a87fb6 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -47,7 +47,7 @@ etc. are not supported. Functions --------- -.. function:: compile(regex_str) +.. function:: compile(regex_str, [flags]) Compile regular expression, return `regex ` object. @@ -65,6 +65,7 @@ Functions .. data:: DEBUG Flag value, display debug information about compiled expression. + (Availability depends on `MicroPython port`.) .. _regex: -- cgit v1.2.3 From 5b1b80a8dbceb9be67dfd894cdf2a49a7426fd68 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 8 Nov 2017 00:24:39 +0200 Subject: docs/ure: Emphasize not supported features more. Plus, additional descriptions/formatting. --- docs/library/ure.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'docs/library') diff --git a/docs/library/ure.rst b/docs/library/ure.rst index 9a5a87fb6..f54614f04 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -15,8 +15,9 @@ Supported operators are: ``'.'`` Match any character. -``'[]'`` - Match set of characters. Individual characters and ranges are supported. +``'[...]'`` + Match set of characters. Individual characters and ranges are supported, + including negated sets (e.g. ``[^a-c]``). ``'^'`` @@ -36,12 +37,13 @@ Supported operators are: ``'|'`` -``'()'`` +``'(...)'`` Grouping. Each group is capturing (a substring it captures can be accessed with `match.group()` method). -Counted repetitions (``{m,n}``), more advanced assertions, named groups, -etc. are not supported. +**NOT SUPPORTED**: Counted repetitions (``{m,n}``), more advanced assertions +(``\b``, ``\B``), named groups (``(?P...)``), non-capturing groups +(``(?:...)``), etc. Functions -- cgit v1.2.3 From 579b86451dba202d573c4c22790ebe3d8ddac060 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 10 Nov 2017 00:09:43 +0200 Subject: docs/_thread: Add a placeholder docs for _thread module. Doesn't list specific API calls yet, the purpose is to let user know that the module exists. --- docs/library/_thread.rst | 12 ++++++++++++ docs/library/index.rst | 2 ++ 2 files changed, 14 insertions(+) create mode 100644 docs/library/_thread.rst (limited to 'docs/library') diff --git a/docs/library/_thread.rst b/docs/library/_thread.rst new file mode 100644 index 000000000..47c1c2392 --- /dev/null +++ b/docs/library/_thread.rst @@ -0,0 +1,12 @@ +:mod:`_thread` -- multithreading support +======================================== + +.. module:: _thread + :synopsis: multithreading support + +|see_cpython_module| :mod:`python:_thread`. + +This module implements multithreading support. + +This module is highly experimental and its API is not yet fully settled +and not yet described in this documentation. diff --git a/docs/library/index.rst b/docs/library/index.rst index 0789ea43d..b141abf1e 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -88,6 +88,7 @@ it will fallback to loading the built-in ``ujson`` module. ustruct.rst utime.rst uzlib.rst + _thread.rst .. only:: port_pyboard @@ -114,6 +115,7 @@ it will fallback to loading the built-in ``ujson`` module. ustruct.rst utime.rst uzlib.rst + _thread.rst .. only:: port_wipy -- cgit v1.2.3 From 31550a52e4b9ff5797755b54c415e365ab1d64d7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 6 Oct 2017 10:57:51 +1100 Subject: docs/library/network: Enhance AbstractNIC.status to take an argument. The argument is optional and if given should be a string naming the status variable to query. --- docs/library/network.rst | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'docs/library') diff --git a/docs/library/network.rst b/docs/library/network.rst index 99a7c242c..a1190a574 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -98,10 +98,20 @@ parameter should be `id`. duration and other parameters. Where possible, parameter names should match those in connect(). - .. method:: status() + .. method:: status([param]) - Return detailed status of the interface, values are dependent - on the network medium/technology. + Query dynamic status information of the interface. When called with no + argument the return value describes the network link status. Otherwise + *param* should be a string naming the particular status parameter to + retrieve. + + The return types and values are dependent on the network + medium/technology. Some of the parameters that may be supported are: + + * WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal + * WiFi AP: use ``'stations'`` to retrieve a list of all the STAs + connected to the AP. The list contains tuples of the form + (MAC, RSSI). .. method:: ifconfig([(ip, subnet, gateway, dns)]) @@ -118,7 +128,7 @@ parameter should be `id`. Get or set general network interface parameters. These methods allow to work with additional parameters beyond standard IP configuration (as dealt with by `ifconfig()`). These include network-specific and hardware-specific - parameters and status values. For setting parameters, the keyword argument + parameters. For setting parameters, the keyword argument syntax should be used, and multiple parameters can be set at once. For querying, a parameter name should be quoted as a string, and only one parameter can be queried at a time:: @@ -128,8 +138,6 @@ parameter should be `id`. # Query params one by one print(ap.config('essid')) print(ap.config('channel')) - # Extended status information also available this way - print(sta.config('rssi')) .. only:: port_pyboard -- cgit v1.2.3 From ec1e9a10a73d9c5c3771a5797e9eceb62475b197 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sun, 12 Nov 2017 06:13:45 +0000 Subject: docs: Add notes on heap allocation caused by bound method refs. --- docs/library/micropython.rst | 11 ++++++++++- docs/reference/isr_rules.rst | 29 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'docs/library') diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index c13a7391b..d1f923e31 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -112,5 +112,14 @@ Functions the heap may be locked) and scheduling a function to call later will lift those restrictions. - There is a finite stack to hold the scheduled functions and `schedule` + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite stack to hold the scheduled functions and `schedule()` will raise a `RuntimeError` if the stack is full. diff --git a/docs/reference/isr_rules.rst b/docs/reference/isr_rules.rst index 2db261c09..dfdee048c 100644 --- a/docs/reference/isr_rules.rst +++ b/docs/reference/isr_rules.rst @@ -124,6 +124,32 @@ A means of creating an object without employing a class or globals is as follows The compiler instantiates the default ``buf`` argument when the function is loaded for the first time (usually when the module it's in is imported). +An instance of object creation occurs when a reference to a bound method is +created. This means that an ISR cannot pass a bound method to a function. One +solution is to create a reference to the bound method in the class constructor +and to pass that reference in the ISR. For example: + +.. code:: python + + class Foo(): + def __init__(self): + self.bar_ref = self.bar # Allocation occurs here + self.x = 0.1 + tim = pyb.Timer(4) + tim.init(freq=2) + tim.callback(self.cb) + + def bar(self, _): + self.x *= 1.2 + print(self.x) + + def cb(self, t): + # Passing self.bar would cause allocation. + micropython.schedule(self.bar_ref, 0) + +Other techniques are to define and instantiate the method in the constructor +or to pass :meth:`Foo.bar` with the argument *self*. + Use of Python objects ~~~~~~~~~~~~~~~~~~~~~ @@ -179,6 +205,9 @@ interrupt occurs while the previous callback is executing, a further instance of for execution; this will run after the current instance has completed. A sustained high interrupt repetition rate therefore carries a risk of unconstrained queue growth and eventual failure with a ``RuntimeError``. +If the callback to be passed to `schedule()` is a bound method, consider the +note in "Creation of Python objects". + Exceptions ---------- -- cgit v1.2.3 From 067bf849d29ab46319740a10561a112376415f51 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 23 Nov 2017 18:03:32 +0200 Subject: docs/uselect: poll: Explicitly specify that no-timeout value is -1. --- docs/library/uselect.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'docs/library') diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index beffce69a..b9e5da999 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -50,10 +50,11 @@ Methods Modify the *eventmask* for *obj*. -.. method:: poll.poll([timeout]) +.. method:: poll.poll(timeout=-1) - Wait for at least one of the registered objects to become ready. Returns - list of (``obj``, ``event``, ...) tuples, ``event`` element specifies + Wait for at least one of the registered objects to become ready, with optional + timeout in milliseconds (if *timeout* arg is not specified or -1, there is no + timeout). Returns list of (``obj``, ``event``, ...) tuples, ``event`` element specifies which events happened with a stream and is a combination of ``select.POLL*`` constants described above. There may be other elements in tuple, depending on a platform and version, so don't assume that its size is 2. In case of -- cgit v1.2.3 From c23cc4cc81a3e437528d8c94e55bfe58db87ea86 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 26 Oct 2017 23:09:17 +0300 Subject: docs/uctypes: Typo/article fixes. --- docs/library/uctypes.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'docs/library') diff --git a/docs/library/uctypes.rst b/docs/library/uctypes.rst index 2a9c4dd5c..164e0eb9d 100644 --- a/docs/library/uctypes.rst +++ b/docs/library/uctypes.rst @@ -8,7 +8,7 @@ This module implements "foreign data interface" for MicroPython. The idea behind it is similar to CPython's ``ctypes`` modules, but the actual API is different, streamlined and optimized for small size. The basic idea of the module is to define data structure layout with about the same power as the -C language allows, and the access it using familiar dot-syntax to reference +C language allows, and then access it using familiar dot-syntax to reference sub-fields. .. seealso:: @@ -43,7 +43,7 @@ Following are encoding examples for various field types: i.e. value is a 2-tuple, first element of which is offset, and second is a structure descriptor dictionary (note: offsets in recursive descriptors - are relative to a structure it defines). + are relative to the structure it defines). * Arrays of primitive types:: @@ -86,9 +86,9 @@ Following are encoding examples for various field types: BF_POS and BF_LEN positions, respectively. Bitfield position is counted from the least significant bit, and is the number of right-most bit of a field (in other words, it's a number of bits a scalar needs to be shifted - right to extra the bitfield). + right to extract the bitfield). - In the example above, first UINT16 value will be extracted at offset 0 + In the example above, first a UINT16 value will be extracted at offset 0 (this detail may be important when accessing hardware registers, where particular access size and alignment are required), and then bitfield whose rightmost bit is least-significant bit of this UINT16, and length @@ -99,7 +99,7 @@ Following are encoding examples for various field types: in particular, example above will access least-significant byte of UINT16 in both little- and big-endian structures. But it depends on the least significant bit being numbered 0. Some targets may use different - numbering in their native ABI, but ``uctypes`` always uses normalized + numbering in their native ABI, but ``uctypes`` always uses the normalized numbering described above. Module contents -- cgit v1.2.3 From 50cffcfe2c479fac9d815cfb28c19e1854070d56 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 26 Oct 2017 23:11:09 +0300 Subject: docs/uctypes: Tweak descriptor reference to hopefully be easier to follow. Put offset first in OR expressions, and use "offset" var instead of hardcoded numbers. Hopefully, this will make it more self-describing and show patterns better. --- docs/library/uctypes.rst | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'docs/library') diff --git a/docs/library/uctypes.rst b/docs/library/uctypes.rst index 164e0eb9d..c938d74a8 100644 --- a/docs/library/uctypes.rst +++ b/docs/library/uctypes.rst @@ -29,16 +29,16 @@ Following are encoding examples for various field types: * Scalar types:: - "field_name": uctypes.UINT32 | 0 + "field_name": offset | uctypes.UINT32 in other words, value is scalar type identifier ORed with field offset (in bytes) from the start of the structure. * Recursive structures:: - "sub": (2, { - "b0": uctypes.UINT8 | 0, - "b1": uctypes.UINT8 | 1, + "sub": (offset, { + "b0": 0 | uctypes.UINT8, + "b1": 1 | uctypes.UINT8, }) i.e. value is a 2-tuple, first element of which is offset, and second is @@ -47,7 +47,7 @@ Following are encoding examples for various field types: * Arrays of primitive types:: - "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2), + "arr": (offset | uctypes.ARRAY, size | uctypes.UINT8), i.e. value is a 2-tuple, first element of which is ARRAY flag ORed with offset, and second is scalar element type ORed number of elements @@ -55,7 +55,7 @@ Following are encoding examples for various field types: * Arrays of aggregate types:: - "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}), + "arr2": (offset | uctypes.ARRAY, size, {"b": 0 | uctypes.UINT8}), i.e. value is a 3-tuple, first element of which is ARRAY flag ORed with offset, second is a number of elements in array, and third is @@ -63,21 +63,21 @@ Following are encoding examples for various field types: * Pointer to a primitive type:: - "ptr": (uctypes.PTR | 0, uctypes.UINT8), + "ptr": (offset | uctypes.PTR, uctypes.UINT8), i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, and second is scalar element type. * Pointer to an aggregate type:: - "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}), + "ptr2": (offset | uctypes.PTR, {"b": 0 | uctypes.UINT8}), i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, second is descriptor of type pointed to. * Bitfields:: - "bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN, + "bitf0": offset | uctypes.BFUINT16 | lsbit << uctypes.BF_POS | bitsize << uctypes.BF_LEN, i.e. value is type of scalar value containing given bitfield (typenames are similar to scalar types, but prefixes with "BF"), ORed with offset for @@ -91,9 +91,10 @@ Following are encoding examples for various field types: In the example above, first a UINT16 value will be extracted at offset 0 (this detail may be important when accessing hardware registers, where particular access size and alignment are required), and then bitfield - whose rightmost bit is least-significant bit of this UINT16, and length - is 8 bits, will be extracted - effectively, this will access - least-significant byte of UINT16. + whose rightmost bit is *lsbit* bit of this UINT16, and length + is *bitsize* bits, will be extracted. For example, if *lsbit* is 0 and + *bitsize* is 8, then effectively it will access least-significant byte + of UINT16. Note that bitfield operations are independent of target byte endianness, in particular, example above will access least-significant byte of UINT16 -- cgit v1.2.3 From f59c6b48aed765fc0eb3785686ffb11f2efc8eae Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 26 Nov 2017 09:55:02 +0200 Subject: docs/uselect: Describe POLLHUP/POLLERR semantics in more details. Per POSIX, http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html these flags aren't valid in the input eventmask. Instead, they can be returned in unsolicited manner in the output eventmask at any time. --- docs/library/uselect.rst | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'docs/library') diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index b9e5da999..aa70bec69 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -35,12 +35,15 @@ Methods Register *obj* for polling. *eventmask* is logical OR of: - * ``select.POLLIN`` - data available for reading - * ``select.POLLOUT`` - more data can be written - * ``select.POLLERR`` - error occurred - * ``select.POLLHUP`` - end of stream/connection termination detected + * `uselect.POLLIN` - data available for reading + * `uselect.POLLOUT` - more data can be written - *eventmask* defaults to ``select.POLLIN | select.POLLOUT``. + Note that flags like `uselect.POLLHUP` and `uselect.POLLERR` are + *not* valid as input eventmask (these are unsolicited events which + will be returned from `poll()` regardless of whether they are asked + for). This semantics is per POSIX. + + *eventmask* defaults to ``uselect.POLLIN | uselect.POLLOUT``. .. method:: poll.unregister(obj) @@ -52,15 +55,21 @@ Methods .. method:: poll.poll(timeout=-1) - Wait for at least one of the registered objects to become ready, with optional - timeout in milliseconds (if *timeout* arg is not specified or -1, there is no - timeout). Returns list of (``obj``, ``event``, ...) tuples, ``event`` element specifies - which events happened with a stream and is a combination of ``select.POLL*`` - constants described above. There may be other elements in tuple, depending - on a platform and version, so don't assume that its size is 2. In case of - timeout, an empty list is returned. - - Timeout is in milliseconds. + Wait for at least one of the registered objects to become ready or have an + exceptional condition, with optional timeout in milliseconds (if *timeout* + arg is not specified or -1, there is no timeout). + + Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in + tuple, depending on a platform and version, so don't assume that its size is 2. + The ``event`` element specifies which events happened with a stream and + is a combination of ``uselect.POLL*`` constants described above. Note that + flags `uselect.POLLHUP` and `uselect.POLLERR` can be returned at any time + (even if were not asked for), and must be acted on accordingly (the + corresponding stream unregistered from poll and likely closed), because + otherwise all further invocations of `poll()` may return immediately with + these flags set for this stream again. + + In case of timeout, an empty list is returned. .. admonition:: Difference to CPython :class: attention -- cgit v1.2.3 From 7d25a192206f7effa47c24a52607f00efe86e2ef Mon Sep 17 00:00:00 2001 From: Paul Carver Date: Sun, 26 Nov 2017 11:29:55 -0500 Subject: docs/library/utime: Fix incorrect example with ticks_diff args order. The parameter order in the example for ticks_diff was incorrect. If it's "too early" that means that scheduled time is greater than current time and if it's "running late" then scheduled time would be less than current time. --- docs/library/utime.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/library') diff --git a/docs/library/utime.rst b/docs/library/utime.rst index a39f5ee73..7fe83f5ab 100644 --- a/docs/library/utime.rst +++ b/docs/library/utime.rst @@ -187,14 +187,14 @@ Functions # This code snippet is not optimized now = time.ticks_ms() scheduled_time = task.scheduled_time() - if ticks_diff(now, scheduled_time) > 0: + if ticks_diff(scheduled_time, now) > 0: print("Too early, let's nap") - sleep_ms(ticks_diff(now, scheduled_time)) + sleep_ms(ticks_diff(scheduled_time, now)) task.run() - elif ticks_diff(now, scheduled_time) == 0: + elif ticks_diff(scheduled_time, now) == 0: print("Right at time!") task.run() - elif ticks_diff(now, scheduled_time) < 0: + elif ticks_diff(scheduled_time, now) < 0: print("Oops, running late, tell task to run faster!") task.run(run_faster=true) -- cgit v1.2.3 From cb9da2279b021ea7a916cbf16dd0e05c009c22bb Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 30 Nov 2017 20:32:49 +0200 Subject: docs/uselect: ipoll: Fix grammar/wording of one-shot flag description. --- docs/library/uselect.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/library') diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index aa70bec69..211b2a4a8 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -83,10 +83,10 @@ Methods way to poll on streams. If *flags* is 1, one-shot behavior for events is employed: streams for - which events happened, event mask will be automatically reset (equivalent - to ``poll.modify(obj, 0)``), so new events for such a stream won't be - processed until new mask is set with `poll.modify()`. This behavior is - useful for asynchronous I/O schedulers. + which events happened will have their event masks automatically reset + (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream + won't be processed until new mask is set with `poll.modify()`. This + behavior is useful for asynchronous I/O schedulers. .. admonition:: Difference to CPython :class: attention -- cgit v1.2.3 From 4fee35a32c600d603034b6eb077a55899513ba4d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 3 Dec 2017 15:07:46 +0200 Subject: docs/glossary: Describe the callee-owned tuple concept. --- docs/library/uselect.rst | 4 ++-- docs/reference/glossary.rst | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'docs/library') diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index 211b2a4a8..f88ab7d1d 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -78,8 +78,8 @@ Methods .. method:: poll.ipoll(timeout=-1, flags=0) - Like :meth:`poll.poll`, but instead returns an iterator which yields - `callee-owned tuples`. This function provides efficient, allocation-free + Like :meth:`poll.poll`, but instead returns an iterator which yields a + `callee-owned tuple`. This function provides an efficient, allocation-free way to poll on streams. If *flags* is 1, one-shot behavior for events is employed: streams for diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index 4cd3d84cc..b6153550c 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -15,6 +15,29 @@ Glossary may also refer to "boardless" ports like :term:`Unix port `). + callee-owned tuple + A tuple returned by some builtin function/method, containing data + which is valid for a limited time, usually until next call to the + same function (or a group of related functions). After next call, + data in the tuple may be changed. This leads to the following + restriction on the usage of callee-owned tuples - references to + them cannot be stored. The only valid operation is extracting + values from them (including making a copy). Callee-owned tuples + is a MicroPython-specific construct (not available in the general + Python language), introduced for memory allocation optimization. + The idea is that callee-owned tuple is allocated once and stored + on the callee side. Subsequent calls don't require allocation, + allowing to return multiple values when allocation is not possible + (e.g. in interrupt context) or not desirable (because allocation + inherently leads to memory fragmentation). Note that callee-owned + tuples are effectively mutable tuples, making an exception to + Python's rule that tuples are immutable. (It may be interesting + why tuples were used for such a purpose then, instead of mutable + lists - the reason for that is that lists are mutable from user + application side too, so a user could do things to a callee-owned + list which the callee doesn't expect and could lead to problems; + a tuple is protected from this.) + CPython CPython is the reference implementation of Python programming language, and the most well-known one, which most of the people -- cgit v1.2.3 From 140acc9a322c1b575d30115604fb1d3250277c0d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 3 Dec 2017 15:50:37 +0200 Subject: docs/uerrno: Fix xref-vs-code markup. --- docs/library/uerrno.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/library') diff --git a/docs/library/uerrno.rst b/docs/library/uerrno.rst index 0cdcc8448..e336eb5c5 100644 --- a/docs/library/uerrno.rst +++ b/docs/library/uerrno.rst @@ -17,7 +17,7 @@ Constants Error codes, based on ANSI C/POSIX standard. All error codes start with "E". As mentioned above, inventory of the codes depends on `MicroPython port`. Errors are usually accessible as ``exc.args[0]`` - where `exc` is an instance of `OSError`. Usage example:: + where ``exc`` is an instance of `OSError`. Usage example:: try: uos.mkdir("my_dir") -- cgit v1.2.3 From 3ff7040c8ab268777e940a9bed4aa7c24f50ba31 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 4 Dec 2017 18:36:20 +0200 Subject: docs/library: Add xrefs to "stream" dictionary entry for many modules. --- docs/library/btree.rst | 2 +- docs/library/machine.UART.rst | 2 +- docs/library/pyb.UART.rst | 2 +- docs/library/pyb.USB_VCP.rst | 4 ++-- docs/library/sys.rst | 6 +++--- docs/library/uio.rst | 2 +- docs/library/uos.rst | 2 +- docs/library/uselect.rst | 4 ++-- docs/library/usocket.rst | 4 ++-- docs/library/ussl.rst | 4 ++-- docs/library/uzlib.rst | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) (limited to 'docs/library') diff --git a/docs/library/btree.rst b/docs/library/btree.rst index 8fac67e8d..3578acd8f 100644 --- a/docs/library/btree.rst +++ b/docs/library/btree.rst @@ -5,7 +5,7 @@ :synopsis: simple BTree database The ``btree`` module implements a simple key-value database using external -storage (disk files, or in general case, a random-access stream). Keys are +storage (disk files, or in general case, a random-access `stream`). Keys are stored sorted in the database, and besides efficient retrieval by a key value, a database also supports efficient ordered range scans (retrieval of values with the keys in a given range). On the application interface diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index 983ef0a94..1574f17db 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -24,7 +24,7 @@ are supported. WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2. -A UART object acts like a stream object and reading and writing is done +A UART object acts like a `stream` object and reading and writing is done using the standard stream methods:: uart.read(10) # read 10 characters, returns a bytes object diff --git a/docs/library/pyb.UART.rst b/docs/library/pyb.UART.rst index 76f347ffa..c299c838e 100644 --- a/docs/library/pyb.UART.rst +++ b/docs/library/pyb.UART.rst @@ -23,7 +23,7 @@ UART objects can be created and initialised using:: *Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits are supported. -A UART object acts like a stream object and reading and writing is done +A UART object acts like a `stream` object and reading and writing is done using the standard stream methods:: uart.read(10) # read 10 characters, returns a bytes object diff --git a/docs/library/pyb.USB_VCP.rst b/docs/library/pyb.USB_VCP.rst index 80cc40cdd..3bc6c749c 100644 --- a/docs/library/pyb.USB_VCP.rst +++ b/docs/library/pyb.USB_VCP.rst @@ -4,7 +4,7 @@ class USB_VCP -- USB virtual comm port ====================================== -The USB_VCP class allows creation of an object representing the USB +The USB_VCP class allows creation of a `stream`-like object representing the USB virtual comm port. It can be used to read and write data over USB to the connected host. @@ -47,7 +47,7 @@ Methods Read at most ``nbytes`` from the serial device and return them as a bytes object. If ``nbytes`` is not specified then the method reads all available bytes from the serial device. - USB_VCP stream implicitly works in non-blocking mode, + USB_VCP `stream` implicitly works in non-blocking mode, so if no pending data available, this method will return immediately with ``None`` value. diff --git a/docs/library/sys.rst b/docs/library/sys.rst index d49577306..f2d96cb8c 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -104,15 +104,15 @@ Constants .. data:: stderr - Standard error stream. + Standard error `stream`. .. data:: stdin - Standard input stream. + Standard input `stream`. .. data:: stdout - Standard output stream. + Standard output `stream`. .. data:: version diff --git a/docs/library/uio.rst b/docs/library/uio.rst index 7042a9e37..7e6c93228 100644 --- a/docs/library/uio.rst +++ b/docs/library/uio.rst @@ -6,7 +6,7 @@ |see_cpython_module| :mod:`python:io`. -This module contains additional types of stream (file-like) objects +This module contains additional types of `stream` (file-like) objects and helper functions. Conceptual hierarchy diff --git a/docs/library/uos.rst b/docs/library/uos.rst index 43bf69cc0..c7fa4b308 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -91,7 +91,7 @@ Functions .. function:: dupterm(stream_object, index=0) - Duplicate or switch the MicroPython terminal (the REPL) on the given stream-like + Duplicate or switch the MicroPython terminal (the REPL) on the given `stream`-like object. The *stream_object* argument must implement the ``readinto()`` and ``write()`` methods. The stream should be in non-blocking mode and ``readinto()`` should return ``None`` if there is no data available for reading. diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index f88ab7d1d..fb43f7e63 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -7,7 +7,7 @@ |see_cpython_module| :mod:`python:select`. This module provides functions to efficiently wait for events on multiple -streams (select streams which are ready for operations). +`streams ` (select streams which are ready for operations). Functions --------- @@ -33,7 +33,7 @@ Methods .. method:: poll.register(obj[, eventmask]) - Register *obj* for polling. *eventmask* is logical OR of: + Register `stream` *obj* for polling. *eventmask* is logical OR of: * `uselect.POLLIN` - data available for reading * `uselect.POLLOUT` - more data can be written diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst index fab05b652..de55fc14c 100644 --- a/docs/library/usocket.rst +++ b/docs/library/usocket.rst @@ -12,7 +12,7 @@ This module provides access to the BSD socket interface. .. admonition:: Difference to CPython :class: attention - For efficiency and consistency, socket objects in MicroPython implement a stream + For efficiency and consistency, socket objects in MicroPython implement a `stream` (file-like) interface directly. In CPython, you need to convert a socket to a file-like object using `makefile()` method. This method is still supported by MicroPython (but is a no-op), so where compatibility with CPython matters, @@ -248,7 +248,7 @@ Methods Not every `MicroPython port` supports this method. A more portable and generic solution is to use `uselect.poll` object. This allows to wait on multiple objects at the same time (and not just on sockets, but on generic - stream objects which support polling). Example:: + `stream` objects which support polling). Example:: # Instead of: s.settimeout(1.0) # time in seconds diff --git a/docs/library/ussl.rst b/docs/library/ussl.rst index 3ec609f67..903a351f4 100644 --- a/docs/library/ussl.rst +++ b/docs/library/ussl.rst @@ -15,9 +15,9 @@ Functions .. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None) - Takes a stream *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), + Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), and returns an instance of ssl.SSLSocket, which wraps the underlying stream in - an SSL context. Returned object has the usual stream interface methods like + an SSL context. Returned object has the usual `stream` interface methods like `read()`, `write()`, etc. In MicroPython, the returned object does not expose socket interface and methods like `recv()`, `send()`. In particular, a server-side SSL socket should be created from a normal socket returned from diff --git a/docs/library/uzlib.rst b/docs/library/uzlib.rst index fb1746fe8..0b399f228 100644 --- a/docs/library/uzlib.rst +++ b/docs/library/uzlib.rst @@ -25,7 +25,7 @@ Functions .. class:: DecompIO(stream, wbits=0) - Create a stream wrapper which allows transparent decompression of + Create a `stream` wrapper which allows transparent decompression of compressed data in another *stream*. This allows to process compressed streams with data larger than available heap size. In addition to values described in :func:`decompress`, *wbits* may take values -- cgit v1.2.3 From 34247465c34113bb26f6c9582ea31f31b0ea0d1b Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sat, 15 Jul 2017 15:53:47 +0200 Subject: extmod/modframebuf: Add 2-bit color format (GS2_HMSB). This format is used in 2-color LED matrices and in e-ink displays like SSD1606. --- docs/library/framebuf.rst | 4 +++ extmod/modframebuf.c | 30 +++++++++++++++++++++ tests/extmod/framebuf2.py | 62 +++++++++++++++++++++++++++++++++++++++++++ tests/extmod/framebuf2.py.exp | 57 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 tests/extmod/framebuf2.py create mode 100644 tests/extmod/framebuf2.py.exp (limited to 'docs/library') diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 74c9f8564..4f0026e38 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -148,6 +148,10 @@ Constants Red Green Blue (16-bit, 5+6+5) color format +.. data:: framebuf.GS2_HMSB + + Grayscale (2-bit) color format + .. data:: framebuf.GS4_HMSB Grayscale (4-bit) color format diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 20e40d579..f2dc4e858 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -54,6 +54,7 @@ typedef struct _mp_framebuf_p_t { // constants for formats #define FRAMEBUF_MVLSB (0) #define FRAMEBUF_RGB565 (1) +#define FRAMEBUF_GS2_HMSB (5) #define FRAMEBUF_GS4_HMSB (2) #define FRAMEBUF_MHLSB (3) #define FRAMEBUF_MHMSB (4) @@ -130,6 +131,30 @@ STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, i } } +// Functions for GS2_HMSB format + +STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2]; + uint8_t shift = (x & 0x3) << 1; + uint8_t mask = 0x3 << shift; + uint8_t color = (col & 0x3) << shift; + *pixel = color | (*pixel & (~mask)); +} + +STATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + uint8_t pixel = ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2]; + uint8_t shift = (x & 0x3) << 1; + return (pixel >> shift) & 0x3; +} + +STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + for (int xx=x; xx < x+w; xx++) { + for (int yy=y; yy < y+h; yy++) { + gs2_hmsb_setpixel(fb, xx, yy, col); + } + } +} + // Functions for GS4_HMSB format STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { @@ -184,6 +209,7 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, STATIC mp_framebuf_p_t formats[] = { [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect}, [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect}, + [FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect}, [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect}, [FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, [FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, @@ -240,6 +266,9 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size case FRAMEBUF_MHMSB: o->stride = (o->stride + 7) & ~7; break; + case FRAMEBUF_GS2_HMSB: + o->stride = (o->stride + 3) & ~3; + break; case FRAMEBUF_GS4_HMSB: o->stride = (o->stride + 1) & ~1; break; @@ -579,6 +608,7 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_MVLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_VLSB), MP_ROM_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) }, { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) }, diff --git a/tests/extmod/framebuf2.py b/tests/extmod/framebuf2.py new file mode 100644 index 000000000..a313170eb --- /dev/null +++ b/tests/extmod/framebuf2.py @@ -0,0 +1,62 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print('%u' % ((buf[(x + y * w) // 4] >> ((x & 3) << 1)) & 3), end='') + print() + print("-->8--") + +w = 8 +h = 5 +buf = bytearray(w * h // 4) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS2_HMSB) + +# fill +fbuf.fill(3) +printbuf() +fbuf.fill(0) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 1) +fbuf.pixel(3, 0, 2) +fbuf.pixel(0, 4, 3) +fbuf.pixel(3, 4, 2) +printbuf() + +# get pixel +print(fbuf.pixel(0, 4), fbuf.pixel(1, 1)) + +# scroll +fbuf.fill(0) +fbuf.pixel(2, 2, 3) +printbuf() +fbuf.scroll(0, 1) +printbuf() +fbuf.scroll(1, 0) +printbuf() +fbuf.scroll(-1, -2) +printbuf() + +w2 = 2 +h2 = 3 +buf2 = bytearray(w2 * h2 // 4) +fbuf2 = framebuf.FrameBuffer(buf2, w2, h2, framebuf.GS2_HMSB) + +# blit +fbuf2.fill(0) +fbuf2.pixel(0, 0, 1) +fbuf2.pixel(0, 2, 2) +fbuf2.pixel(1, 0, 1) +fbuf2.pixel(1, 2, 2) +fbuf.fill(3) +fbuf.blit(fbuf2, 3, 3, 0) +fbuf.blit(fbuf2, -1, -1, 0) +fbuf.blit(fbuf2, 16, 16, 0) +printbuf() diff --git a/tests/extmod/framebuf2.py.exp b/tests/extmod/framebuf2.py.exp new file mode 100644 index 000000000..c53e518a6 --- /dev/null +++ b/tests/extmod/framebuf2.py.exp @@ -0,0 +1,57 @@ +--8<-- +33333333 +33333333 +33333333 +33333333 +33333333 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00000000 +00000000 +-->8-- +--8<-- +10020000 +00000000 +00000000 +00000000 +30020000 +-->8-- +3 0 +--8<-- +00000000 +00000000 +00300000 +00000000 +00000000 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00300000 +00000000 +-->8-- +--8<-- +00000000 +00000000 +00000000 +00030000 +00000000 +-->8-- +--8<-- +00000000 +00300000 +00000000 +00030000 +00000000 +-->8-- +--8<-- +33333333 +23333333 +33333333 +33311333 +33333333 +-->8-- -- cgit v1.2.3 From 46b35356e1727365dd5a33fcf3a722fda82c8b08 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 14 Dec 2017 17:36:13 +1100 Subject: extmod/modframebuf: Add 8-bit greyscale format (GS8). --- docs/library/framebuf.rst | 4 ++++ extmod/modframebuf.c | 24 ++++++++++++++++++++++++ tests/extmod/framebuf8.py | 32 ++++++++++++++++++++++++++++++++ tests/extmod/framebuf8.py.exp | 15 +++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 tests/extmod/framebuf8.py create mode 100644 tests/extmod/framebuf8.py.exp (limited to 'docs/library') diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 4f0026e38..ed4b78ab1 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -155,3 +155,7 @@ Constants .. data:: framebuf.GS4_HMSB Grayscale (4-bit) color format + +.. data:: framebuf.GS8 + + Grayscale (8-bit) color format diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index f2dc4e858..a7f6ba905 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -56,6 +56,7 @@ typedef struct _mp_framebuf_p_t { #define FRAMEBUF_RGB565 (1) #define FRAMEBUF_GS2_HMSB (5) #define FRAMEBUF_GS4_HMSB (2) +#define FRAMEBUF_GS8 (6) #define FRAMEBUF_MHLSB (3) #define FRAMEBUF_MHMSB (4) @@ -206,11 +207,31 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, } } +// Functions for GS8 format + +STATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)]; + *pixel = col & 0xff; +} + +STATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + return ((uint8_t*)fb->buf)[(x + y * fb->stride)]; +} + +STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)]; + while (h--) { + memset(pixel, col, w); + pixel += fb->stride; + } +} + STATIC mp_framebuf_p_t formats[] = { [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect}, [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect}, [FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect}, [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect}, + [FRAMEBUF_GS8] = {gs8_setpixel, gs8_getpixel, gs8_fill_rect}, [FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, [FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, }; @@ -272,6 +293,8 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size case FRAMEBUF_GS4_HMSB: o->stride = (o->stride + 1) & ~1; break; + case FRAMEBUF_GS8: + break; default: mp_raise_ValueError("invalid format"); } @@ -610,6 +633,7 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) }, { MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) }, { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) }, + { MP_ROM_QSTR(MP_QSTR_GS8), MP_ROM_INT(FRAMEBUF_GS8) }, { MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) }, { MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) }, }; diff --git a/tests/extmod/framebuf8.py b/tests/extmod/framebuf8.py new file mode 100644 index 000000000..b6899aae9 --- /dev/null +++ b/tests/extmod/framebuf8.py @@ -0,0 +1,32 @@ +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print('%02x' % buf[(x + y * w)], end='') + print() + print("-->8--") + +w = 8 +h = 5 +buf = bytearray(w * h) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS8) + +# fill +fbuf.fill(0x55) +printbuf() + +# put pixel +fbuf.pixel(0, 0, 0x11) +fbuf.pixel(w - 1, 0, 0x22) +fbuf.pixel(0, h - 1, 0x33) +fbuf.pixel(w - 1, h - 1, 0xff) +printbuf() + +# get pixel +print(hex(fbuf.pixel(0, h - 1)), hex(fbuf.pixel(1, 1))) diff --git a/tests/extmod/framebuf8.py.exp b/tests/extmod/framebuf8.py.exp new file mode 100644 index 000000000..01d8976fe --- /dev/null +++ b/tests/extmod/framebuf8.py.exp @@ -0,0 +1,15 @@ +--8<-- +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +-->8-- +--8<-- +1155555555555522 +5555555555555555 +5555555555555555 +5555555555555555 +33555555555555ff +-->8-- +0x33 0x55 -- cgit v1.2.3 From 5de064fbd056944e393be9355855eee6562fecdb Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 23 Dec 2017 21:21:08 +0200 Subject: docs/library/index: Elaborate uPy libraries intro. --- docs/library/index.rst | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'docs/library') diff --git a/docs/library/index.rst b/docs/library/index.rst index b141abf1e..af1a0ff69 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -9,34 +9,36 @@ MicroPython libraries * MicroPython implements a subset of Python functionality for each module. * To ease extensibility, MicroPython versions of standard Python modules - usually have ``u`` (micro) prefix. + usually have ``u`` ("micro") prefix. * Any particular MicroPython variant or port may miss any feature/function - described in this general documentation, due to resource constraints. + described in this general documentation (due to resource constraints or + other limitations). This chapter describes modules (function and class libraries) which are built -into MicroPython. There are a few categories of modules: +into MicroPython. There are a few categories of such modules: * Modules which implement a subset of standard Python functionality and are not intended to be extended by the user. * Modules which implement a subset of Python functionality, with a provision for extension by the user (via Python code). * Modules which implement MicroPython extensions to the Python standard libraries. -* Modules specific to a particular port and thus not portable. +* Modules specific to a particular `MicroPython port` and thus not portable. -Note about the availability of modules and their contents: This documentation +Note about the availability of the modules and their contents: This documentation in general aspires to describe all modules and functions/classes which are -implemented in MicroPython. However, MicroPython is highly configurable, and +implemented in MicroPython project. However, MicroPython is highly configurable, and each port to a particular board/embedded system makes available only a subset of MicroPython libraries. For officially supported ports, there is an effort to either filter out non-applicable items, or mark individual descriptions with "Availability:" clauses describing which ports provide a given feature. + With that in mind, please still be warned that some functions/classes -in a module (or even the entire module) described in this documentation may be -unavailable in a particular build of MicroPython on a particular board. The +in a module (or even the entire module) described in this documentation **may be +unavailable** in a particular build of MicroPython on a particular system. The best place to find general information of the availability/non-availability of a particular feature is the "General Information" section which contains -information pertaining to a specific port. +information pertaining to a specific `MicroPython port`. Beyond the built-in libraries described in this documentation, many more modules from the Python standard library, as well as further MicroPython @@ -58,9 +60,9 @@ what done by the `micropython-lib` project mentioned above). On some embedded platforms, where it may be cumbersome to add Python-level wrapper modules to achieve naming compatibility with CPython, micro-modules are available both by their u-name, and also by their non-u-name. The -non-u-name can be overridden by a file of that name in your package path. -For example, ``import json`` will first search for a file ``json.py`` or -directory ``json`` and load that package if it is found. If nothing is found, +non-u-name can be overridden by a file of that name in your library path (``sys.path``). +For example, ``import json`` will first search for a file ``json.py`` (or package +directory ``json``) and load that module if it is found. If nothing is found, it will fallback to loading the built-in ``ujson`` module. .. only:: port_unix -- cgit v1.2.3 From e708e87139ec2bd2c94ce33c0f7b873ef89d3827 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Feb 2018 15:52:49 +1100 Subject: docs/library/pyb.rst: Add note about availability of USB MSC-only mode. --- docs/library/pyb.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'docs/library') diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 799160145..141c270b3 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -278,7 +278,8 @@ Miscellaneous functions - ``None``: disables USB - ``'VCP'``: enable with VCP (Virtual COM Port) interface - - ``'VCP+MSC'``: enable with VCP and MSC (mass storage device class) + - ``'MSC'``: enable with MSC (mass storage device class) interface + - ``'VCP+MSC'``: enable with VCP and MSC - ``'VCP+HID'``: enable with VCP and HID (human interface device) For backwards compatibility, ``'CDC'`` is understood to mean -- cgit v1.2.3 From 9e8b7b1b635889e365efe3e240c5fe97c0f8de0a Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Feb 2018 11:31:34 +1100 Subject: docs/library/ujson: Update to conform with docs conventions. The formatting of exception objects is done as per CPython conventions, eg: :exc:`TypeError` --- docs/library/ujson.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/library') diff --git a/docs/library/ujson.rst b/docs/library/ujson.rst index 0932d0ab5..82b35ecde 100644 --- a/docs/library/ujson.rst +++ b/docs/library/ujson.rst @@ -14,9 +14,9 @@ Functions .. function:: dumps(obj) - Return ``obj`` represented as a JSON string. + Return *obj* represented as a JSON string. .. function:: loads(str) - Parse the JSON ``str`` and return an object. Raises ValueError if the + Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the string is not correctly formed. -- cgit v1.2.3 From e05fca4ef399b321464cae6f0ba2ddc16b58a1b2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Feb 2018 15:48:24 +1100 Subject: docs/library/ujson: Document dump() and load() functions. --- docs/library/ujson.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'docs/library') diff --git a/docs/library/ujson.rst b/docs/library/ujson.rst index 82b35ecde..5668eb21a 100644 --- a/docs/library/ujson.rst +++ b/docs/library/ujson.rst @@ -12,10 +12,23 @@ data format. Functions --------- +.. function:: dump(obj, stream) + + Serialise *obj* to a JSON string, writing it to the given *stream*. + .. function:: dumps(obj) Return *obj* represented as a JSON string. +.. function:: load(stream) + + Parse the given *stream*, interpreting it as a JSON string and + deserialising the data to a Python object. The resulting object is + returned. + + Parsing continues until end-of-file is encountered. + A :exc:`ValueError` is raised if the data in *stream* is not correctly formed. + .. function:: loads(str) Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the -- cgit v1.2.3 From c5fe610ba15468e1d92d7b6d5f5962f7595e3324 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 26 Feb 2018 16:41:13 +1100 Subject: esp8266/modnetwork: Implement WLAN.status('rssi') for STA interface. This will return the RSSI of the AP that the STA is connected to. --- docs/library/network.rst | 6 +++++- ports/esp8266/modnetwork.c | 24 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'docs/library') diff --git a/docs/library/network.rst b/docs/library/network.rst index a1190a574..a113209e0 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -383,10 +383,11 @@ parameter should be `id`. * 0 -- visible * 1 -- hidden - .. method:: wlan.status() + .. method:: wlan.status([param]) Return the current status of the wireless connection. + When called with no argument the return value describes the network link status. The possible statuses are defined as constants: * ``STAT_IDLE`` -- no connection and no activity, @@ -396,6 +397,9 @@ parameter should be `id`. * ``STAT_CONNECT_FAIL`` -- failed due to other problems, * ``STAT_GOT_IP`` -- connection successful. + When called with one argument *param* should be a string naming the status + parameter to retrieve. Supported parameters in WiFI STA mode are: ``'rssi'``. + .. method:: wlan.isconnected() In case of STA mode, returns ``True`` if connected to a WiFi access diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index f7da5b751..00a84c446 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -150,14 +150,26 @@ STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect); -STATIC mp_obj_t esp_status(mp_obj_t self_in) { - wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->if_id == STATION_IF) { - return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status()); +STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) { + wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 1) { + // Get link status + if (self->if_id == STATION_IF) { + return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status()); + } + return MP_OBJ_NEW_SMALL_INT(-1); + } else { + // Get specific status parameter + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_rssi: + if (self->if_id == STATION_IF) { + return MP_OBJ_NEW_SMALL_INT(wifi_station_get_rssi()); + } + } + mp_raise_ValueError("unknown status param"); } - return MP_OBJ_NEW_SMALL_INT(-1); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status); STATIC mp_obj_t *esp_scan_list = NULL; -- cgit v1.2.3 From 6e09320b4c5b3b6630acb70ee5c28154a757e61a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Mar 2018 19:07:39 +1100 Subject: docs/library/usocket: Make xref to uerrno explicitly a module reference. --- docs/library/usocket.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/library') diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst index de55fc14c..3ae477a9a 100644 --- a/docs/library/usocket.rst +++ b/docs/library/usocket.rst @@ -99,7 +99,7 @@ Functions of error in this function. MicroPython doesn't have ``socket.gaierror`` and raises OSError directly. Note that error numbers of `getaddrinfo()` form a separate namespace and may not match error numbers from - `uerrno` module. To distinguish `getaddrinfo()` errors, they are + the :mod:`uerrno` module. To distinguish `getaddrinfo()` errors, they are represented by negative numbers, whereas standard system errors are positive numbers (error numbers are accessible using ``e.args[0]`` property from an exception object). The use of negative values is a provisional -- cgit v1.2.3 From a5fb699d87ffa178736021c4763d323be54e87d4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Mar 2018 19:10:45 +1100 Subject: docs/library/micropython: Describe optimisation levels for opt_level(). --- docs/library/micropython.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'docs/library') diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index d1f923e31..a6ea738ed 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -33,6 +33,18 @@ Functions compilation of scripts, and returns ``None``. Otherwise it returns the current optimisation level. + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + .. function:: alloc_emergency_exception_buf(size) Allocate *size* bytes of RAM for the emergency exception buffer (a good -- cgit v1.2.3 From 63b003d52350b4c8468d000f544ae9a634de1493 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Mar 2018 14:49:25 +1100 Subject: docs/library/uos: Create sections for distinct parts and document uname. --- docs/library/uos.rst | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'docs/library') diff --git a/docs/library/uos.rst b/docs/library/uos.rst index c7fa4b308..85754c5a1 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -6,11 +6,32 @@ |see_cpython_module| :mod:`python:os`. -The ``uos`` module contains functions for filesystem access and ``urandom`` -function. +The ``uos`` module contains functions for filesystem access and mounting, +terminal redirection and duplication, and the ``uname`` and ``urandom`` +functions. -Functions ---------- +General functions +----------------- + +.. function:: uname() + + Return a tuple (possibly a named tuple) containing information about the + underlying machine and/or its operating system. The tuple has five fields + in the following order, each of them being a string: + + * ``sysname`` -- the name of the underlying system + * ``nodename`` -- the network name (can be the same as ``sysname``) + * ``release`` -- the version of the underlying system + * ``version`` -- the MicroPython version and build date + * ``machine`` -- an identifier for the underlying hardware (eg board, CPU) + +.. function:: urandom(n) + + Return a bytes object with *n* random bytes. Whenever possible, it is + generated by the hardware random number generator. + +Filesystem access +----------------- .. function:: chdir(path) @@ -84,10 +105,8 @@ Functions Sync all filesystems. -.. function:: urandom(n) - - Return a bytes object with n random bytes. Whenever possible, it is - generated by the hardware random number generator. +Terminal redirection and duplication +------------------------------------ .. function:: dupterm(stream_object, index=0) -- cgit v1.2.3 From 8359210e71ee0c46434ef8b1056627597f0bf0bf Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Mar 2018 14:50:38 +1100 Subject: docs/library/uos: Document mount, umount, VfsFat and block devices. --- docs/library/uos.rst | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) (limited to 'docs/library') diff --git a/docs/library/uos.rst b/docs/library/uos.rst index 85754c5a1..85adb6a4d 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -127,3 +127,119 @@ Terminal redirection and duplication the slot given by *index*. The function returns the previous stream-like object in the given slot. + +Filesystem mounting +------------------- + +Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple +"real" filesystems within this VFS. Filesystem objects can be mounted at either +the root of the VFS, or at a subdirectory that lives in the root. This allows +dynamic and flexible configuration of the filesystem that is seen by Python +programs. Ports that have this functionality provide the :func:`mount` and +:func:`umount` functions, and possibly various filesystem implementations +represented by VFS classes. + +.. function:: mount(fsobj, mount_point, \*, readonly) + + Mount the filesystem object *fsobj* at the location in the VFS given by the + *mount_point* string. *fsobj* can be a a VFS object that has a ``mount()`` + method, or a block device. If it's a block device then the filesystem type + is automatically detected (an exception is raised if no filesystem was + recognised). *mount_point* may be ``'/'`` to mount *fsobj* at the root, + or ``'/'`` to mount it at a subdirectory under the root. + + If *readonly* is ``True`` then the filesystem is mounted read-only. + + During the mount process the method ``mount()`` is called on the filesystem + object. + + Will raise ``OSError(EPERM)`` if *mount_point* is already mounted. + +.. function:: umount(mount_point) + + Unmount a filesystem. *mount_point* can be a string naming the mount location, + or a previously-mounted filesystem object. During the unmount process the + method ``umount()`` is called on the filesystem object. + + Will raise ``OSError(EINVAL)`` if *mount_point* is not found. + +.. class:: VfsFat(block_dev) + + Create a filesystem object that uses the FAT filesystem format. Storage of + the FAT filesystem is provided by *block_dev*. + Objects created by this constructor can be mounted using :func:`mount`. + + .. staticmethod:: mkfs(block_dev) + + Build a FAT filesystem on *block_dev*. + +Block devices +------------- + +A block device is an object which implements the block protocol, which is a set +of methods described below by the :class:`AbstractBlockDev` class. A concrete +implementation of this class will usually allow access to the memory-like +functionality a piece of hardware (like flash memory). A block device can be +used by a particular filesystem driver to store the data for its filesystem. + +.. class:: AbstractBlockDev(...) + + Construct a block device object. The parameters to the constructor are + dependent on the specific block device. + + .. method:: readblocks(block_num, buf) + + Starting at *block_num*, read blocks from the device into *buf* (an array + of bytes). The number of blocks to read is given by the length of *buf*, + which will be a multiple of the block size. + + .. method:: writeblocks(block_num, buf) + + Starting at *block_num*, write blocks from *buf* (an array of bytes) to + the device. The number of blocks to write is given by the length of *buf*, + which will be a multiple of the block size. + + .. method:: ioctl(op, arg) + + Control the block device and query its parameters. The operation to + perform is given by *op* which is one of the following integers: + + - 1 -- initialise the device (*arg* is unused) + - 2 -- shutdown the device (*arg* is unused) + - 3 -- sync the device (*arg* is unused) + - 4 -- get a count of the number of blocks, should return an integer + (*arg* is unused) + - 5 -- get the number of bytes in a block, should return an integer, + or ``None`` in which case the default value of 512 is used + (*arg* is unused) + +By way of example, the following class will implement a block device that stores +its data in RAM using a ``bytearray``:: + + class RAMBlockDev: + def __init__(self, block_size, num_blocks): + self.block_size = block_size + self.data = bytearray(block_size * num_blocks) + + def readblocks(self, block_num, buf): + for i in range(len(buf)): + buf[i] = self.data[block_num * self.block_size + i] + + def writeblocks(self, block_num, buf): + for i in range(len(buf)): + self.data[block_num * self.block_size + i] = buf[i] + + def ioctl(self, op, arg): + if op == 4: # get number of blocks + return len(self.data) // self.block_size + if op == 5: # get block size + return self.block_size + +It can be used as follows:: + + import uos + + bdev = RAMBlockDev(512, 50) + uos.VfsFat.mkfs(bdev) + vfs = uos.VfsFat(bdev) + uos.mount(vfs, '/ramdisk') -- cgit v1.2.3 From 4d3a92c67c9b1550eaf07d06ed74de996ee8fa3b Mon Sep 17 00:00:00 2001 From: Tom Collins Date: Thu, 8 Mar 2018 16:02:26 -0800 Subject: extmod/vfs_fat: Add file size as 4th element of uos.ilistdir tuple. --- docs/library/uos.rst | 8 ++++++-- extmod/vfs.c | 4 +--- extmod/vfs_fat.c | 5 +++-- tests/extmod/vfs_fat_fileio1.py.exp | 2 +- tests/extmod/vfs_fat_fileio2.py.exp | 8 ++++---- tests/extmod/vfs_fat_oldproto.py.exp | 2 +- tests/extmod/vfs_fat_ramdisk.py.exp | 4 ++-- 7 files changed, 18 insertions(+), 15 deletions(-) (limited to 'docs/library') diff --git a/docs/library/uos.rst b/docs/library/uos.rst index 85adb6a4d..27f339bb1 100644 --- a/docs/library/uos.rst +++ b/docs/library/uos.rst @@ -43,11 +43,11 @@ Filesystem access .. function:: ilistdir([dir]) - This function returns an iterator which then yields 3-tuples corresponding to + This function returns an iterator which then yields tuples corresponding to the entries in the directory that it is listing. With no argument it lists the current directory, otherwise it lists the directory given by *dir*. - The 3-tuples have the form *(name, type, inode)*: + The tuples have the form *(name, type, inode[, size])*: - *name* is a string (or bytes if *dir* is a bytes object) and is the name of the entry; @@ -55,6 +55,10 @@ Filesystem access directories and 0x8000 for regular files; - *inode* is an integer corresponding to the inode of the file, and may be 0 for filesystems that don't have such a notion. + - Some platforms may return a 4-tuple that includes the entry's *size*. For + file entries, *size* is an integer representing the size of the file + or -1 if unknown. Its meaning is currently undefined for directory + entries. .. function:: listdir([dir]) diff --git a/extmod/vfs.c b/extmod/vfs.c index 105a80a8d..0585de1c7 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -366,9 +366,7 @@ mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) { mp_obj_t dir_list = mp_obj_new_list(0, NULL); mp_obj_t next; while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { - mp_obj_t *items; - mp_obj_get_array_fixed_n(next, 3, &items); - mp_obj_list_append(dir_list, items[0]); + mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL)); } return dir_list; } diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 0177f5129..5666a6b0c 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -142,8 +142,8 @@ STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { // Note that FatFS already filters . and .., so we don't need to - // make 3-tuple with info about this entry - mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + // make 4-tuple with info about this entry + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); if (self->is_str) { t->items[0] = mp_obj_new_str(fn, strlen(fn)); } else { @@ -157,6 +157,7 @@ STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG); } t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number + t->items[3] = mp_obj_new_int_from_uint(fno.fsize); return MP_OBJ_FROM_PTR(t); } diff --git a/tests/extmod/vfs_fat_fileio1.py.exp b/tests/extmod/vfs_fat_fileio1.py.exp index 2d4792aa3..4eb50402c 100644 --- a/tests/extmod/vfs_fat_fileio1.py.exp +++ b/tests/extmod/vfs_fat_fileio1.py.exp @@ -10,7 +10,7 @@ e o d True -[('foo_dir', 16384, 0)] +[('foo_dir', 16384, 0, 0)] MemoryError x0 x1 diff --git a/tests/extmod/vfs_fat_fileio2.py.exp b/tests/extmod/vfs_fat_fileio2.py.exp index 118dee26b..268405364 100644 --- a/tests/extmod/vfs_fat_fileio2.py.exp +++ b/tests/extmod/vfs_fat_fileio2.py.exp @@ -3,9 +3,9 @@ True True b'data in file' True -[('sub_file.txt', 32768, 0), ('file.txt', 32768, 0)] -[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)] -[('foo_dir', 16384, 0), ('moved-to-root.txt', 32768, 0)] +[('sub_file.txt', 32768, 0, 11), ('file.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 12)] +[('foo_dir', 16384, 0, 0), ('moved-to-root.txt', 32768, 0, 8)] new text -[('moved-to-root.txt', 32768, 0)] +[('moved-to-root.txt', 32768, 0, 8)] ENOSPC: True diff --git a/tests/extmod/vfs_fat_oldproto.py.exp b/tests/extmod/vfs_fat_oldproto.py.exp index ab8338cbb..b97468316 100644 --- a/tests/extmod/vfs_fat_oldproto.py.exp +++ b/tests/extmod/vfs_fat_oldproto.py.exp @@ -1,3 +1,3 @@ -[('file.txt', 32768, 0)] +[('file.txt', 32768, 0, 6)] hello! [] diff --git a/tests/extmod/vfs_fat_ramdisk.py.exp b/tests/extmod/vfs_fat_ramdisk.py.exp index ccd0f7134..ef6cf1e72 100644 --- a/tests/extmod/vfs_fat_ramdisk.py.exp +++ b/tests/extmod/vfs_fat_ramdisk.py.exp @@ -3,7 +3,7 @@ True statvfs: (512, 512, 16, 16, 16, 0, 0, 0, 0, 255) getcwd: / True -[('foo_file.txt', 32768, 0)] +[('foo_file.txt', 32768, 0, 6)] stat root: (16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) stat file: (32768, 0, 0, 0, 0, 0, 6) True @@ -12,5 +12,5 @@ getcwd: /foo_dir [] True getcwd: / -[(b'foo_file.txt', 32768, 0), (b'foo_dir', 16384, 0)] +[(b'foo_file.txt', 32768, 0, 6), (b'foo_dir', 16384, 0, 0)] ENOENT: True -- cgit v1.2.3 From 0db49c37a4e8d2516ea0206f4e800b907cd4221f Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 15:50:51 +1100 Subject: docs: Fix some references and RST markup to eliminate Sphinx warnings. --- docs/library/array.rst | 6 +++--- docs/library/lcd160cr.rst | 4 ++-- docs/library/pyb.Switch.rst | 2 +- docs/library/uio.rst | 4 ++-- docs/library/uselect.rst | 8 ++++---- docs/library/ussl.rst | 6 +++--- docs/reference/constrained.rst | 4 ++-- docs/reference/packages.rst | 4 ++-- docs/reference/speed_python.rst | 10 +++++----- 9 files changed, 24 insertions(+), 24 deletions(-) (limited to 'docs/library') diff --git a/docs/library/array.rst b/docs/library/array.rst index d096c6ec4..f837b0343 100644 --- a/docs/library/array.rst +++ b/docs/library/array.rst @@ -16,14 +16,14 @@ Classes .. class:: array.array(typecode, [iterable]) Create array with elements of given type. Initial contents of the - array are given by an `iterable`. If it is not provided, an empty + array are given by *iterable*. If it is not provided, an empty array is created. .. method:: append(val) - Append new element to the end of array, growing it. + Append new element *val* to the end of array, growing it. .. method:: extend(iterable) - Append new elements as contained in an iterable to the end of + Append new elements as contained in *iterable* to the end of array, growing it. diff --git a/docs/library/lcd160cr.rst b/docs/library/lcd160cr.rst index 567994640..bb8e6da22 100644 --- a/docs/library/lcd160cr.rst +++ b/docs/library/lcd160cr.rst @@ -172,7 +172,7 @@ Drawing text ------------ To draw text one sets the position, color and font, and then uses -`write` to draw the text. +`LCD160CR.write` to draw the text. .. method:: LCD160CR.set_pos(x, y) @@ -279,7 +279,7 @@ Touch screen methods .. method:: LCD160CR.is_touched() Returns a boolean: ``True`` if there is currently a touch force on the screen, - `False` otherwise. + ``False`` otherwise. .. method:: LCD160CR.get_touch() diff --git a/docs/library/pyb.Switch.rst b/docs/library/pyb.Switch.rst index e5ab6bd84..1edcbf848 100644 --- a/docs/library/pyb.Switch.rst +++ b/docs/library/pyb.Switch.rst @@ -38,7 +38,7 @@ Methods .. method:: Switch.value() - Get the switch state. Returns `True` if pressed down, otherwise `False`. + Get the switch state. Returns ``True`` if pressed down, otherwise ``False``. .. method:: Switch.callback(fun) diff --git a/docs/library/uio.rst b/docs/library/uio.rst index 7e6c93228..81420702d 100644 --- a/docs/library/uio.rst +++ b/docs/library/uio.rst @@ -81,7 +81,7 @@ Functions Open a file. Builtin ``open()`` function is aliased to this function. All ports (which provide access to file system) are required to support - `mode` parameter, but support for other arguments vary by port. + *mode* parameter, but support for other arguments vary by port. Classes ------- @@ -103,7 +103,7 @@ Classes text-mode I/O (similar to a normal file opened with "t" modifier). `BytesIO` is used for binary-mode I/O (similar to a normal file opened with "b" modifier). Initial contents of file-like objects - can be specified with `string` parameter (should be normal string + can be specified with *string* parameter (should be normal string for `StringIO` or bytes object for `BytesIO`). All the usual file methods like ``read()``, ``write()``, ``seek()``, ``flush()``, ``close()`` are available on these objects, and additionally, a diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst index fb43f7e63..77d458473 100644 --- a/docs/library/uselect.rst +++ b/docs/library/uselect.rst @@ -35,10 +35,10 @@ Methods Register `stream` *obj* for polling. *eventmask* is logical OR of: - * `uselect.POLLIN` - data available for reading - * `uselect.POLLOUT` - more data can be written + * ``uselect.POLLIN`` - data available for reading + * ``uselect.POLLOUT`` - more data can be written - Note that flags like `uselect.POLLHUP` and `uselect.POLLERR` are + Note that flags like ``uselect.POLLHUP`` and ``uselect.POLLERR`` are *not* valid as input eventmask (these are unsolicited events which will be returned from `poll()` regardless of whether they are asked for). This semantics is per POSIX. @@ -63,7 +63,7 @@ Methods tuple, depending on a platform and version, so don't assume that its size is 2. The ``event`` element specifies which events happened with a stream and is a combination of ``uselect.POLL*`` constants described above. Note that - flags `uselect.POLLHUP` and `uselect.POLLERR` can be returned at any time + flags ``uselect.POLLHUP`` and ``uselect.POLLERR`` can be returned at any time (even if were not asked for), and must be acted on accordingly (the corresponding stream unregistered from poll and likely closed), because otherwise all further invocations of `poll()` may return immediately with diff --git a/docs/library/ussl.rst b/docs/library/ussl.rst index 903a351f4..be84dc054 100644 --- a/docs/library/ussl.rst +++ b/docs/library/ussl.rst @@ -18,10 +18,10 @@ Functions Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type), and returns an instance of ssl.SSLSocket, which wraps the underlying stream in an SSL context. Returned object has the usual `stream` interface methods like - `read()`, `write()`, etc. In MicroPython, the returned object does not expose - socket interface and methods like `recv()`, `send()`. In particular, a + ``read()``, ``write()``, etc. In MicroPython, the returned object does not expose + socket interface and methods like ``recv()``, ``send()``. In particular, a server-side SSL socket should be created from a normal socket returned from - `accept()` on a non-SSL listening server socket. + :meth:`~usocket.socket.accept()` on a non-SSL listening server socket. Depending on the underlying module implementation in a particular `MicroPython port`, some or all keyword arguments above may be not supported. diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst index e7de459bc..edac0ae68 100644 --- a/docs/reference/constrained.rst +++ b/docs/reference/constrained.rst @@ -185,7 +185,7 @@ a file it will save RAM if this is done in a piecemeal fashion. Rather than creating a large string object, create a substring and feed it to the stream before dealing with the next. -The best way to create dynamic strings is by means of the string `format` +The best way to create dynamic strings is by means of the string ``format()`` method: .. code:: @@ -259,7 +259,7 @@ were a string. **Runtime compiler execution** The Python funcitons `eval` and `exec` invoke the compiler at runtime, which -requires significant amounts of RAM. Note that the `pickle` library from +requires significant amounts of RAM. Note that the ``pickle`` library from `micropython-lib` employs `exec`. It may be more RAM efficient to use the `ujson` library for object serialisation. diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst index e1609985a..8be2461c2 100644 --- a/docs/reference/packages.rst +++ b/docs/reference/packages.rst @@ -42,7 +42,7 @@ size, which means that to uncompress a compressed stream, 32KB of contguous memory needs to be allocated. This requirement may be not satisfiable on low-memory devices, which may have total memory available less than that amount, and even if not, a contiguous block like that -may be hard to allocate due to `memory fragmentation`. To accommodate +may be hard to allocate due to memory fragmentation. To accommodate these constraints, MicroPython distribution packages use Gzip compression with the dictionary size of 4K, which should be a suitable compromise with still achieving some compression while being able to uncompressed @@ -243,7 +243,7 @@ the data files as "resources", and abstracting away access to them. Python supports resource access using its "setuptools" library, using ``pkg_resources`` module. MicroPython, following its usual approach, implements subset of the functionality of that module, specifically -`pkg_resources.resource_stream(package, resource)` function. +``pkg_resources.resource_stream(package, resource)`` function. The idea is that an application calls this function, passing a resource identifier, which is a relative path to data file within the specified package (usually top-level application package). It diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index 279a1bbcd..4db60ec14 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -63,8 +63,8 @@ used for communication with a device. A typical driver will create the buffer in constructor and use it in its I/O methods which will be called repeatedly. The MicroPython libraries typically provide support for pre-allocated buffers. For -example, objects which support stream interface (e.g., file or UART) provide `read()` -method which allocates new buffer for read data, but also a `readinto()` method +example, objects which support stream interface (e.g., file or UART) provide ``read()`` +method which allocates new buffer for read data, but also a ``readinto()`` method to read data into an existing buffer. Floating Point @@ -109,10 +109,10 @@ the 10K buffer go (be ready for garbage collection), instead of making a long-living memoryview and keeping 10K blocked for GC. Nonetheless, `memoryview` is indispensable for advanced preallocated buffer -management. `readinto()` method discussed above puts data at the beginning +management. ``readinto()`` method discussed above puts data at the beginning of buffer and fills in entire buffer. What if you need to put data in the middle of existing buffer? Just create a memoryview into the needed section -of buffer and pass it to `readinto()`. +of buffer and pass it to ``readinto()``. Identifying the slowest section of code --------------------------------------- @@ -326,7 +326,7 @@ standard approach would be to write mypin.value(mypin.value() ^ 1) # mypin was instantiated as an output pin -This involves the overhead of two calls to the `Pin` instance's :meth:`~machine.Pin.value()` +This involves the overhead of two calls to the :class:`~machine.Pin` instance's :meth:`~machine.Pin.value()` method. This overhead can be eliminated by performing a read/write to the relevant bit of the chip's GPIO port output data register (odr). To facilitate this the ``stm`` module provides a set of constants providing the addresses of the relevant registers. -- cgit v1.2.3 From d91a1989f5e914c20e8bd559fcca3dc91887f167 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 16:12:32 +1100 Subject: docs/library/pyb.CAN: Update markup to use latest doc conventions. --- docs/library/pyb.CAN.rst | 60 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'docs/library') diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 232d04d96..7a3a5e939 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -24,11 +24,11 @@ Constructors .. class:: pyb.CAN(bus, ...) - Construct a CAN object on the given bus. ``bus`` can be 1-2, or 'YA' or 'YB'. + Construct a CAN object on the given bus. *bus* can be 1-2, or ``'YA'`` or ``'YB'``. With no additional parameters, the CAN object is created but not initialised (it has the settings from the last initialisation of the bus, if any). If extra arguments are given, the bus is initialised. - See ``init`` for parameters of initialisation. + See :meth:`CAN.init` for parameters of initialisation. The physical pins of the CAN busses are: @@ -42,7 +42,7 @@ Class Methods Reset and disable all filter banks and assign how many banks should be available for CAN(1). STM32F405 has 28 filter banks that are shared between the two available CAN bus controllers. - This function configures how many filter banks should be assigned to each. ``nr`` is the number of banks + This function configures how many filter banks should be assigned to each. *nr* is the number of banks that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2). At boot, 14 banks are assigned to each controller. @@ -53,16 +53,16 @@ Methods Initialise the CAN bus with the given parameters: - - ``mode`` is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK - - if ``extframe`` is True then the bus uses extended identifiers in the frames + - *mode* is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK + - if *extframe* is True then the bus uses extended identifiers in the frames (29 bits); otherwise it uses standard 11 bit identifiers - - ``prescaler`` is used to set the duration of 1 time quanta; the time quanta + - *prescaler* is used to set the duration of 1 time quanta; the time quanta will be the input clock (PCLK1, see :meth:`pyb.freq()`) divided by the prescaler - - ``sjw`` is the resynchronisation jump width in units of the time quanta; + - *sjw* is the resynchronisation jump width in units of the time quanta; it can be 1, 2, 3, 4 - - ``bs1`` defines the location of the sample point in units of the time quanta; + - *bs1* defines the location of the sample point in units of the time quanta; it can be between 1 and 1024 inclusive - - ``bs2`` defines the location of the transmit point in units of the time quanta; + - *bs2* defines the location of the transmit point in units of the time quanta; it can be between 1 and 16 inclusive The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN @@ -89,13 +89,13 @@ Methods Configure a filter bank: - - ``bank`` is the filter bank that is to be configured. - - ``mode`` is the mode the filter should operate in. - - ``fifo`` is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter. - - ``params`` is an array of values the defines the filter. The contents of the array depends on the ``mode`` argument. + - *bank* is the filter bank that is to be configured. + - *mode* is the mode the filter should operate in. + - *fifo* is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter. + - *params* is an array of values the defines the filter. The contents of the array depends on the *mode* argument. +-----------+---------------------------------------------------------+ - |``mode`` |contents of parameter array | + |*mode* |contents of *params* array | +===========+=========================================================+ |CAN.LIST16 |Four 16 bit ids that will be accepted | +-----------+---------------------------------------------------------+ @@ -110,13 +110,13 @@ Methods |CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.| +-----------+---------------------------------------------------------+ - - ``rtr`` is an array of booleans that states if a filter should accept a + - *rtr* is an array of booleans that states if a filter should accept a remote transmission request message. If this argument is not given - then it defaults to False for all entries. The length of the array - depends on the ``mode`` argument. + then it defaults to ``False`` for all entries. The length of the array + depends on the *mode* argument. +-----------+----------------------+ - |``mode`` |length of rtr array | + |*mode* |length of *rtr* array | +===========+======================+ |CAN.LIST16 |4 | +-----------+----------------------+ @@ -131,7 +131,7 @@ Methods Clear and disables a filter bank: - - ``bank`` is the filter bank that is to be cleared. + - *bank* is the filter bank that is to be cleared. .. method:: CAN.any(fifo) @@ -141,8 +141,8 @@ Methods Receive data on the bus: - - ``fifo`` is an integer, which is the FIFO to receive on - - ``timeout`` is the timeout in milliseconds to wait for the receive. + - *fifo* is an integer, which is the FIFO to receive on + - *timeout* is the timeout in milliseconds to wait for the receive. Return value: A tuple containing four values. @@ -155,13 +155,13 @@ Methods Send a message on the bus: - - ``data`` is the data to send (an integer to send, or a buffer object). - - ``id`` is the id of the message to be sent. - - ``timeout`` is the timeout in milliseconds to wait for the send. - - ``rtr`` is a boolean that specifies if the message shall be sent as - a remote transmission request. If ``rtr`` is True then only the length - of ``data`` is used to fill in the DLC slot of the frame; the actual - bytes in ``data`` are unused. + - *data* is the data to send (an integer to send, or a buffer object). + - *id* is the id of the message to be sent. + - *timeout* is the timeout in milliseconds to wait for the send. + - *rtr* is a boolean that specifies if the message shall be sent as + a remote transmission request. If *rtr* is True then only the length + of *data* is used to fill in the DLC slot of the frame; the actual + bytes in *data* are unused. If timeout is 0 the message is placed in a buffer in one of three hardware buffers and the method returns immediately. If all three buffers are in use @@ -175,8 +175,8 @@ Methods Register a function to be called when a message is accepted into a empty fifo: - - ``fifo`` is the receiving fifo. - - ``fun`` is the function to be called when the fifo becomes non empty. + - *fifo* is the receiving fifo. + - *fun* is the function to be called when the fifo becomes non empty. The callback function takes two arguments the first is the can object it self the second is a integer that indicates the reason for the callback. -- cgit v1.2.3 From 823ca03008908d98671393c00b018349d18b46a2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 17:17:33 +1100 Subject: stm32/can: Add "auto_restart" option to constructor and init() method. --- docs/library/pyb.CAN.rst | 4 +++- ports/stm32/can.c | 18 ++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'docs/library') diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 7a3a5e939..6e5b958cf 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -49,7 +49,7 @@ Class Methods Methods ------- -.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8) +.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8, auto_restart=False) Initialise the CAN bus with the given parameters: @@ -64,6 +64,8 @@ Methods it can be between 1 and 1024 inclusive - *bs2* defines the location of the transmit point in units of the time quanta; it can be between 1 and 16 inclusive + - *auto_restart* sets whether the controller will automatically try and restart + communications after entering the bus-off state The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1); diff --git a/ports/stm32/can.c b/ports/stm32/can.c index d73ca95d4..fc0fa98a8 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -307,7 +307,6 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki if (!self->is_enabled) { mp_printf(print, "CAN(%u)", self->can_id); } else { - mp_printf(print, "CAN(%u, CAN.", self->can_id); qstr mode; switch (self->can.Init.Mode) { case CAN_MODE_NORMAL: mode = MP_QSTR_NORMAL; break; @@ -315,19 +314,17 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki case CAN_MODE_SILENT: mode = MP_QSTR_SILENT; break; case CAN_MODE_SILENT_LOOPBACK: default: mode = MP_QSTR_SILENT_LOOPBACK; break; } - mp_printf(print, "%q, extframe=", mode); - if (self->extframe) { - mode = MP_QSTR_True; - } else { - mode = MP_QSTR_False; - } - mp_printf(print, "%q)", mode); + mp_printf(print, "CAN(%u, CAN.%q, extframe=%q, auto_restart=%q)", + self->can_id, + mode, + self->extframe ? MP_QSTR_True : MP_QSTR_False, + (self->can.Instance->MCR & CAN_MCR_ABOM) ? MP_QSTR_True : MP_QSTR_False); } } // init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8) STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_mode, ARG_extframe, ARG_prescaler, ARG_sjw, ARG_bs1, ARG_bs2 }; + enum { ARG_mode, ARG_extframe, ARG_prescaler, ARG_sjw, ARG_bs1, ARG_bs2, ARG_auto_restart }; static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_MODE_NORMAL} }, { MP_QSTR_extframe, MP_ARG_BOOL, {.u_bool = false} }, @@ -335,6 +332,7 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp { MP_QSTR_sjw, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_bs1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 6} }, { MP_QSTR_bs2, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_auto_restart, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; // parse args @@ -352,7 +350,7 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp init->BS1 = ((args[ARG_bs1].u_int - 1) & 0xf) << 16; init->BS2 = ((args[ARG_bs2].u_int - 1) & 7) << 20; init->TTCM = DISABLE; - init->ABOM = DISABLE; + init->ABOM = args[ARG_auto_restart].u_bool ? ENABLE : DISABLE; init->AWUM = DISABLE; init->NART = DISABLE; init->RFLM = DISABLE; -- cgit v1.2.3 From 1272c3c65d895e4694e0c707a98a739706667d23 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 15 Mar 2018 17:29:30 +1100 Subject: stm32/can: Add CAN.restart() method so controller can leave bus-off. --- docs/library/pyb.CAN.rst | 14 +++++++++++++- ports/stm32/can.c | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'docs/library') diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 6e5b958cf..f90e7a8a7 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -65,7 +65,8 @@ Methods - *bs2* defines the location of the transmit point in units of the time quanta; it can be between 1 and 16 inclusive - *auto_restart* sets whether the controller will automatically try and restart - communications after entering the bus-off state + communications after entering the bus-off state; if this is disabled then + :meth:`~CAN.restart()` can be used to leave the bus-off state The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1); @@ -87,6 +88,17 @@ Methods Turn off the CAN bus. +.. method:: CAN.restart() + + Force a software restart of the CAN controller without resetting its + configuration. + + If the controller enters the bus-off state then it will no longer participate + in bus activity. If the controller is not configured to automatically restart + (see :meth:`~CAN.init()`) then this method can be used to trigger a restart, + and the controller will follow the CAN protocol to leave the bus-off state and + go into the error active state. + .. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: diff --git a/ports/stm32/can.c b/ports/stm32/can.c index fc0fa98a8..d5702f6d1 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -467,6 +467,23 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_deinit_obj, pyb_can_deinit); +// Force a software restart of the controller, to allow transmission after a bus error +STATIC mp_obj_t pyb_can_restart(mp_obj_t self_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!self->is_enabled) { + mp_raise_ValueError(NULL); + } + CAN_TypeDef *can = self->can.Instance; + can->MCR |= CAN_MCR_INRQ; + while ((can->MSR & CAN_MSR_INAK) == 0) { + } + can->MCR &= ~CAN_MCR_INRQ; + while ((can->MSR & CAN_MSR_INAK)) { + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_restart_obj, pyb_can_restart); + /// \method any(fifo) /// Return `True` if any message waiting on the FIFO, else `False`. STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) { @@ -824,6 +841,7 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { // instance methods { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_can_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) }, -- cgit v1.2.3 From d7e67fb1b40c40ba24e3a17e73e5f1b5b96f3914 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Mar 2018 17:10:41 +1100 Subject: stm32/can: Add CAN.state() method to get the state of the controller. This is useful for monitoring errors on the bus and knowing when a restart is needed. --- docs/library/pyb.CAN.rst | 22 ++++++++++++++++++++++ ports/stm32/can.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) (limited to 'docs/library') diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index f90e7a8a7..484a00f36 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -99,6 +99,20 @@ Methods and the controller will follow the CAN protocol to leave the bus-off state and go into the error active state. +.. method:: CAN.state() + + Return the state of the controller. The return value can be one of: + + - ``CAN.STOPPED`` -- the controller is completely off and reset; + - ``CAN.ERROR_ACTIVE`` -- the controller is on and in the Error Active state + (both TEC and REC are less than 96); + - ``CAN.ERROR_WARNING`` -- the controller is on and in the Error Warning state + (at least one of TEC or REC is 96 or greater); + - ``CAN.ERROR_PASSIVE`` -- the controller is on and in the Error Passive state + (at least one of TEC or REC is 128 or greater); + - ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity + (TEC overflowed beyond 255). + .. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: @@ -229,6 +243,14 @@ Constants the mode of the CAN bus +.. data:: CAN.STOPPED + CAN.ERROR_ACTIVE + CAN.ERROR_WARNING + CAN.ERROR_PASSIVE + CAN.BUS_OFF + + Possible states of the CAN controller. + .. data:: CAN.LIST16 .. data:: CAN.MASK16 .. data:: CAN.LIST32 diff --git a/ports/stm32/can.c b/ports/stm32/can.c index d5702f6d1..563d15dab 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -45,6 +45,14 @@ #define MASK32 (2) #define LIST32 (3) +enum { + CAN_STATE_STOPPED, + CAN_STATE_ERROR_ACTIVE, + CAN_STATE_ERROR_WARNING, + CAN_STATE_ERROR_PASSIVE, + CAN_STATE_BUS_OFF, +}; + /// \moduleref pyb /// \class CAN - controller area network communication bus /// @@ -484,6 +492,26 @@ STATIC mp_obj_t pyb_can_restart(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_restart_obj, pyb_can_restart); +// Get the state of the controller +STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t state = CAN_STATE_STOPPED; + if (self->is_enabled) { + CAN_TypeDef *can = self->can.Instance; + if (can->ESR & CAN_ESR_BOFF) { + state = CAN_STATE_BUS_OFF; + } else if (can->ESR & CAN_ESR_EPVF) { + state = CAN_STATE_ERROR_PASSIVE; + } else if (can->ESR & CAN_ESR_EWGF) { + state = CAN_STATE_ERROR_WARNING; + } else { + state = CAN_STATE_ERROR_ACTIVE; + } + } + return MP_OBJ_NEW_SMALL_INT(state); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state); + /// \method any(fifo) /// Return `True` if any message waiting on the FIFO, else `False`. STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) { @@ -842,6 +870,7 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_can_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&pyb_can_state_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) }, @@ -861,6 +890,13 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_LIST16), MP_ROM_INT(LIST16) }, { MP_ROM_QSTR(MP_QSTR_MASK32), MP_ROM_INT(MASK32) }, { MP_ROM_QSTR(MP_QSTR_LIST32), MP_ROM_INT(LIST32) }, + + // values for CAN.state() + { MP_ROM_QSTR(MP_QSTR_STOPPED), MP_ROM_INT(CAN_STATE_STOPPED) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_ACTIVE), MP_ROM_INT(CAN_STATE_ERROR_ACTIVE) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_WARNING), MP_ROM_INT(CAN_STATE_ERROR_WARNING) }, + { MP_ROM_QSTR(MP_QSTR_ERROR_PASSIVE), MP_ROM_INT(CAN_STATE_ERROR_PASSIVE) }, + { MP_ROM_QSTR(MP_QSTR_BUS_OFF), MP_ROM_INT(CAN_STATE_BUS_OFF) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_can_locals_dict, pyb_can_locals_dict_table); -- cgit v1.2.3 From a25e6c6b650acf3af742920c1d3a024054c986cb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Mar 2018 18:28:35 +1100 Subject: stm32/can: Add CAN.info() method to retrieve error and tx/rx buf info. --- docs/library/pyb.CAN.rst | 22 +++++++++++++++++ ports/stm32/can.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ ports/stm32/can.h | 1 + ports/stm32/stm32_it.c | 12 ++++++++++ 4 files changed, 97 insertions(+) (limited to 'docs/library') diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 484a00f36..e1ce90d60 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -113,6 +113,28 @@ Methods - ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity (TEC overflowed beyond 255). +.. method:: CAN.info([list]) + + Get information about the controller's error states and TX and RX buffers. + If *list* is provided then it should be a list object with at least 8 entries, + which will be filled in with the information. Otherwise a new list will be + created and filled in. In both cases the return value of the method is the + populated list. + + The values in the list are: + + - TEC value + - REC value + - number of times the controller enterted the Error Warning state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Error Passive state (wrapped + around to 0 after 65535) + - number of times the controller enterted the Bus Off state (wrapped + around to 0 after 65535) + - number of pending TX messages + - number of pending RX messages on fifo 0 + - number of pending RX messages on fifo 1 + .. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 563d15dab..b1bcd1c3e 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -89,6 +89,9 @@ typedef struct _pyb_can_obj_t { bool extframe : 1; byte rx_state0; byte rx_state1; + uint16_t num_error_warning; + uint16_t num_error_passive; + uint16_t num_bus_off; CAN_HandleTypeDef can; } pyb_can_obj_t; @@ -103,6 +106,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { uint32_t GPIO_Pin = 0; uint8_t GPIO_AF_CANx = 0; GPIO_TypeDef* GPIO_Port = NULL; + uint32_t sce_irq = 0; switch (can_obj->can_id) { // CAN1 is on RX,TX = Y3,Y4 = PB9,PB9 @@ -111,6 +115,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { GPIO_AF_CANx = GPIO_AF9_CAN1; GPIO_Port = GPIOB; GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9; + sce_irq = CAN1_SCE_IRQn; __CAN1_CLK_ENABLE(); break; @@ -121,6 +126,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { GPIO_AF_CANx = GPIO_AF9_CAN2; GPIO_Port = GPIOB; GPIO_Pin = GPIO_PIN_12 | GPIO_PIN_13; + sce_irq = CAN2_SCE_IRQn; __CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well __CAN2_CLK_ENABLE(); break; @@ -144,6 +150,14 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) { HAL_CAN_Init(&can_obj->can); can_obj->is_enabled = true; + can_obj->num_error_warning = 0; + can_obj->num_error_passive = 0; + can_obj->num_bus_off = 0; + + __HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG); + + HAL_NVIC_SetPriority(sce_irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN); + HAL_NVIC_EnableIRQ(sce_irq); return true; } @@ -459,6 +473,7 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { if (self->can.Instance == CAN1) { HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN1_SCE_IRQn); __CAN1_FORCE_RESET(); __CAN1_RELEASE_RESET(); __CAN1_CLK_DISABLE(); @@ -466,6 +481,7 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { } else if (self->can.Instance == CAN2) { HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn); HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn); + HAL_NVIC_DisableIRQ(CAN2_SCE_IRQn); __CAN2_FORCE_RESET(); __CAN2_RELEASE_RESET(); __CAN2_CLK_DISABLE(); @@ -512,6 +528,36 @@ STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state); +// Get info about error states and TX/RX buffers +STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { + pyb_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_obj_list_t *list; + if (n_args == 1) { + list = MP_OBJ_TO_PTR(mp_obj_new_list(8, NULL)); + } else { + if (!MP_OBJ_IS_TYPE(args[1], &mp_type_list)) { + mp_raise_TypeError(NULL); + } + list = MP_OBJ_TO_PTR(args[1]); + if (list->len < 8) { + mp_raise_ValueError(NULL); + } + } + CAN_TypeDef *can = self->can.Instance; + uint32_t esr = can->ESR; + list->items[0] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_TEC_Pos & 0xff); + list->items[1] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_REC_Pos & 0xff); + list->items[2] = MP_OBJ_NEW_SMALL_INT(self->num_error_warning); + list->items[3] = MP_OBJ_NEW_SMALL_INT(self->num_error_passive); + list->items[4] = MP_OBJ_NEW_SMALL_INT(self->num_bus_off); + int n_tx_pending = 0x01121223 >> ((can->TSR >> CAN_TSR_TME_Pos & 7) << 2) & 0xf; + list->items[5] = MP_OBJ_NEW_SMALL_INT(n_tx_pending); + list->items[6] = MP_OBJ_NEW_SMALL_INT(can->RF0R >> CAN_RF0R_FMP0_Pos & 3); + list->items[7] = MP_OBJ_NEW_SMALL_INT(can->RF1R >> CAN_RF1R_FMP1_Pos & 3); + return MP_OBJ_FROM_PTR(list); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_can_info_obj, 1, 2, pyb_can_info); + /// \method any(fifo) /// Return `True` if any message waiting on the FIFO, else `False`. STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) { @@ -871,6 +917,7 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) }, { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&pyb_can_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_can_info_obj) }, { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) }, @@ -979,6 +1026,21 @@ void can_rx_irq_handler(uint can_id, uint fifo_id) { } } +void can_sce_irq_handler(uint can_id) { + pyb_can_obj_t *self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1]; + if (self) { + self->can.Instance->MSR = CAN_MSR_ERRI; + uint32_t esr = self->can.Instance->ESR; + if (esr & CAN_ESR_BOFF) { + ++self->num_bus_off; + } else if (esr & CAN_ESR_EPVF) { + ++self->num_error_passive; + } else if (esr & CAN_ESR_EWGF) { + ++self->num_error_warning; + } + } +} + STATIC const mp_stream_p_t can_stream_p = { //.read = can_read, // is read sensible for CAN? //.write = can_write, // is write sensible for CAN? diff --git a/ports/stm32/can.h b/ports/stm32/can.h index b725b5924..54e7deaa5 100644 --- a/ports/stm32/can.h +++ b/ports/stm32/can.h @@ -34,5 +34,6 @@ extern const mp_obj_type_t pyb_can_type; void can_init0(void); void can_deinit(void); void can_rx_irq_handler(uint can_id, uint fifo_id); +void can_sce_irq_handler(uint can_id); #endif // MICROPY_INCLUDED_STM32_CAN_H diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 0ad71771c..77cfcc580 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -749,6 +749,12 @@ void CAN1_RX1_IRQHandler(void) { IRQ_EXIT(CAN1_RX1_IRQn); } +void CAN1_SCE_IRQHandler(void) { + IRQ_ENTER(CAN1_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_1); + IRQ_EXIT(CAN1_SCE_IRQn); +} + void CAN2_RX0_IRQHandler(void) { IRQ_ENTER(CAN2_RX0_IRQn); can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0); @@ -760,6 +766,12 @@ void CAN2_RX1_IRQHandler(void) { can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1); IRQ_EXIT(CAN2_RX1_IRQn); } + +void CAN2_SCE_IRQHandler(void) { + IRQ_ENTER(CAN2_SCE_IRQn); + can_sce_irq_handler(PYB_CAN_2); + IRQ_EXIT(CAN2_SCE_IRQn); +} #endif // MICROPY_HW_ENABLE_CAN #if defined(MICROPY_HW_I2C1_SCL) -- cgit v1.2.3 From b7d576d69a8ef104d4a5538fd09ed97806a15369 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 16 Mar 2018 18:29:43 +1100 Subject: docs/library/pyb.CAN: Clean up documentation of data constants. --- docs/library/pyb.CAN.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'docs/library') diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index e1ce90d60..5fe4c2ecf 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -259,11 +259,11 @@ Constants --------- .. data:: CAN.NORMAL -.. data:: CAN.LOOPBACK -.. data:: CAN.SILENT -.. data:: CAN.SILENT_LOOPBACK + CAN.LOOPBACK + CAN.SILENT + CAN.SILENT_LOOPBACK - the mode of the CAN bus + The mode of the CAN bus used in :meth:`~CAN.init()`. .. data:: CAN.STOPPED CAN.ERROR_ACTIVE @@ -271,11 +271,11 @@ Constants CAN.ERROR_PASSIVE CAN.BUS_OFF - Possible states of the CAN controller. + Possible states of the CAN controller returned from :meth:`~CAN.state()`. .. data:: CAN.LIST16 -.. data:: CAN.MASK16 -.. data:: CAN.LIST32 -.. data:: CAN.MASK32 + CAN.MASK16 + CAN.LIST32 + CAN.MASK32 - the operation mode of a filter + The operation mode of a filter used in :meth:`~CAN.setfilter()`. -- cgit v1.2.3 From 0abbafd42406e4367a80ad996bdd7047ad1e020d Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 19 Mar 2018 15:12:24 +1100 Subject: stm32/can: Add "list" param to CAN.recv() to receive data inplace. This API matches (as close as possible) how other pyb classes allow inplace operations, such as pyb.SPI.recv(buf). --- docs/library/pyb.CAN.rst | 21 +++++++++++++++- ports/stm32/can.c | 62 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 66 insertions(+), 17 deletions(-) (limited to 'docs/library') diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 5fe4c2ecf..09b97a187 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -187,11 +187,12 @@ Methods Return ``True`` if any message waiting on the FIFO, else ``False``. -.. method:: CAN.recv(fifo, \*, timeout=5000) +.. method:: CAN.recv(fifo, list=None, \*, timeout=5000) Receive data on the bus: - *fifo* is an integer, which is the FIFO to receive on + - *list* is an optional list object to be used as the return value - *timeout* is the timeout in milliseconds to wait for the receive. Return value: A tuple containing four values. @@ -201,6 +202,24 @@ Methods - The FMI (Filter Match Index) value. - An array containing the data. + If *list* is ``None`` then a new tuple will be allocated, as well as a new + bytes object to contain the data (as the fourth element in the tuple). + + If *list* is not ``None`` then it should be a list object with a least four + elements. The fourth element should be a memoryview object which is created + from either a bytearray or an array of type 'B' or 'b', and this array must + have enough room for at least 8 bytes. The list object will then be + populated with the first three return values above, and the memoryview object + will be resized inplace to the size of the data and filled in with that data. + The same list and memoryview objects can be reused in subsequent calls to + this method, providing a way of receiving data without using the heap. + For example:: + + buf = bytearray(8) + lst = [0, 0, 0, memoryview(buf)] + # No heap memory is allocated in the following call + can.recv(0, lst) + .. method:: CAN.send(data, id, \*, timeout=0, rtr=False) Send a message on the bus: diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 5b5c4ad3f..bc4f1092c 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -29,8 +29,10 @@ #include #include "py/objtuple.h" +#include "py/objarray.h" #include "py/runtime.h" #include "py/gc.h" +#include "py/binary.h" #include "py/stream.h" #include "py/mperrno.h" #include "py/mphal.h" @@ -645,18 +647,20 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send); -/// \method recv(fifo, *, timeout=5000) +/// \method recv(fifo, list=None, *, timeout=5000) /// /// Receive data on the bus: /// /// - `fifo` is an integer, which is the FIFO to receive on +/// - `list` if not None is a list with at least 4 elements /// - `timeout` is the timeout in milliseconds to wait for the receive. /// /// Return value: buffer of data bytes. STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_fifo, ARG_timeout }; + enum { ARG_fifo, ARG_list, ARG_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_list, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; @@ -700,23 +704,49 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } } - // return the received data - // TODO use a namedtuple (when namedtuple types can be stored in ROM) - mp_obj_tuple_t *tuple = mp_obj_new_tuple(4, NULL); - if (rx_msg.IDE == CAN_ID_STD) { - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); + // Create the tuple, or get the list, that will hold the return values + // Also populate the fourth element, either a new bytes or reuse existing memoryview + mp_obj_t ret_obj = args[ARG_list].u_obj; + mp_obj_t *items; + if (ret_obj == mp_const_none) { + ret_obj = mp_obj_new_tuple(4, NULL); + items = ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(ret_obj))->items; + items[3] = mp_obj_new_bytes(&rx_msg.Data[0], rx_msg.DLC); } else { - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); + // User should provide a list of length at least 4 to hold the values + if (!MP_OBJ_IS_TYPE(ret_obj, &mp_type_list)) { + mp_raise_TypeError(NULL); + } + mp_obj_list_t *list = MP_OBJ_TO_PTR(ret_obj); + if (list->len < 4) { + mp_raise_ValueError(NULL); + } + items = list->items; + // Fourth element must be a memoryview which we assume points to a + // byte-like array which is large enough, and then we resize it inplace + if (!MP_OBJ_IS_TYPE(items[3], &mp_type_memoryview)) { + mp_raise_TypeError(NULL); + } + mp_obj_array_t *mv = MP_OBJ_TO_PTR(items[3]); + if (!(mv->typecode == (0x80 | BYTEARRAY_TYPECODE) + || (mv->typecode | 0x20) == (0x80 | 'b'))) { + mp_raise_ValueError(NULL); + } + mv->len = rx_msg.DLC; + memcpy(mv->items, &rx_msg.Data[0], rx_msg.DLC); } - tuple->items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; - tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); - vstr_t vstr; - vstr_init_len(&vstr, rx_msg.DLC); - for (mp_uint_t i = 0; i < rx_msg.DLC; i++) { - vstr.buf[i] = rx_msg.Data[i]; // Data is uint32_t but holds only 1 byte + + // Populate the first 3 values of the tuple/list + if (rx_msg.IDE == CAN_ID_STD) { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); + } else { + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); } - tuple->items[3] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); - return tuple; + items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; + items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); + + // Return the result + return ret_obj; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv); -- cgit v1.2.3 From 8f11d0b532bd0203c875ad9e3e4efd8a7014ca15 Mon Sep 17 00:00:00 2001 From: T S Date: Tue, 20 Mar 2018 19:57:33 +0100 Subject: docs/library/pyb.ADC.rst: Document new features for ADCAll. --- docs/library/pyb.ADC.rst | 74 ++++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 28 deletions(-) (limited to 'docs/library') diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 51021fdc1..58aae6129 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -10,14 +10,16 @@ class ADC -- analog to digital conversion import pyb - adc = pyb.ADC(pin) # create an analog object from a pin - val = adc.read() # read an analog value + adc = pyb.ADC(pin) # create an analog object from a pin + val = adc.read() # read an analog value - adc = pyb.ADCAll(resolution) # create an ADCAll object - val = adc.read_channel(channel) # read the given channel - val = adc.read_core_temp() # read MCU temperature - val = adc.read_core_vbat() # read MCU VBAT - val = adc.read_core_vref() # read MCU VREF + adc = pyb.ADCAll(resolution) # create an ADCAll object + adc = pyb.ADCAll(resolution, mask) # create an ADCAll object for selected analog channels + val = adc.read_channel(channel) # read the given channel + val = adc.read_core_temp() # read MCU temperature + val = adc.read_core_vbat() # read MCU VBAT + val = adc.read_core_vref() # read MCU VREF + val = adc.read_vref() # read MCU supply voltage Constructors @@ -81,27 +83,42 @@ The ADCAll Object .. only:: port_pyboard - Instantiating this changes all ADC pins to analog inputs. The raw MCU temperature, + Instantiating this changes all masked ADC pins to analog inputs. The preprocessed MCU temperature, VREF and VBAT data can be accessed on ADC channels 16, 17 and 18 respectively. - Appropriate scaling will need to be applied. The temperature sensor on the chip - has poor absolute accuracy and is suitable only for detecting temperature changes. - - The ``ADCAll`` ``read_core_vbat()`` and ``read_core_vref()`` methods read - the backup battery voltage and the (1.21V nominal) reference voltage using the - 3.3V supply as a reference. Assuming the ``ADCAll`` object has been Instantiated with - ``adc = pyb.ADCAll(12)`` the 3.3V supply voltage may be calculated: - - ``v33 = 3.3 * 1.21 / adc.read_core_vref()`` - - If the 3.3V supply is correct the value of ``adc.read_core_vbat()`` will be - valid. If the supply voltage can drop below 3.3V, for example in in battery - powered systems with a discharging battery, the regulator will fail to preserve - the 3.3V supply resulting in an incorrect reading. To produce a value which will - remain valid under these circumstances use the following: - - ``vback = adc.read_core_vbat() * 1.21 / adc.read_core_vref()`` - - It is possible to access these values without incurring the side effects of ``ADCAll``:: + Appropriate scaling is handled according to reference voltage used (usually 3.3V). + The temperature sensor on the chip is factory calibrated and allows to read the die temperature + to +/- 1 degree centigrade. Although this sounds pretty accurate, don't forget that the MCU's internal + temperature is measured. Depending on processing loads and I/O subsystems active the die temperature + may easily be tens of degrees above ambient temperature. On the other hand a pyboard woken up after a + long standby period will show correct ambient temperature within limits mentioned above. + + The ``ADCAll`` ``read_core_vbat()``, ``read_vref()`` and ``read_core_vref()`` methods read + the backup battery voltage, reference voltage and the (1.21V nominal) reference voltage using the + actual supply as a reference. All results are floating point numbers giving direct voltage values. + + ``read_core_vbat()`` returns the voltage of the backup battery. This voltage is also adjusted according + to the actual supply voltage. To avoid analog input overload the battery voltage is measured + via a voltage divider and scaled according to the divider value. To prevent excessive loads + to the backup battery, the voltage divider is only active during ADC conversion. + + ``read_vref()`` is evaluated by measuring the internal voltage reference and backscale it using + factory calibration value of the internal voltage reference. In most cases the reading would be close + to 3.3V. If the pyboard is operated from a battery, the supply voltage may drop to values below 3.3V. + The pyboard will still operate fine as long as the operating conditions are met. With proper settings + of MCU clock, flash access speed and programming mode it is possible to run the pyboard down to + 2 V and still get useful ADC conversion. + + It is very important to make sure analog input voltages never exceed actual supply voltage. + + Other analog input channels (0..15) will return unscaled integer values according to the selected + precision. + + To avoid unwanted activation of analog inputs (channel 0..15) a second prarmeter can be specified. + This parameter is a binary pattern where each requested analog input has the corresponding bit set. + The default value is 0xffffffff which means all analog inputs are active. If just the internal + channels (16..18) are required, the mask value should be 0x70000. + + It is possible to access channle 16..18 values without incurring the side effects of ``ADCAll``:: def adcread(chan): # 16 temp 17 vbat 18 vref assert chan >= 16 and chan <= 18, 'Invalid ADC channel' @@ -140,4 +157,5 @@ The ADCAll Object def temperature(): return 25 + 400 * (3.3 * adcread(16) / 4096 - 0.76) - \ No newline at end of file + Note that this example is only valid for the F405 MCU and all values are not corrected by Vref and + factory calibration data. -- cgit v1.2.3 From 4f40fa5cf4de7a8eabe073493e2df54c8a08ea89 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sun, 4 Mar 2018 09:07:40 +0000 Subject: stm32/adc: Add read_timed_multi() static method, with docs and tests. --- docs/library/pyb.ADC.rst | 53 ++++++++++++++++++++++- ports/stm32/adc.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++ tests/pyb/adc.py | 28 +++++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) (limited to 'docs/library') diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 58aae6129..c2d09ad40 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -76,7 +76,58 @@ Methods for val in buf: # loop over all values print(val) # print the value out - This function does not allocate any memory. + This function does not allocate any heap memory. It has blocking behaviour: + it does not return to the calling program until the buffer is full. + + .. method:: ADC.read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer) + + This is a static method. It can be used to extract relative timing or + phase data from multiple ADC's. + + It reads analog values from multiple ADC's into buffers at a rate set by + the *timer* object. Each time the timer triggers a sample is rapidly + read from each ADC in turn. + + ADC and buffer instances are passed in tuples with each ADC having an + associated buffer. All buffers must be of the same type and length and + the number of buffers must equal the number of ADC's. + + Buffers can be ``bytearray`` or ``array.array`` for example. The ADC values + have 12-bit resolution and are stored directly into the buffer if its element + size is 16 bits or greater. If buffers have only 8-bit elements (eg a + ``bytearray``) then the sample resolution will be reduced to 8 bits. + + *timer* must be a Timer object. The timer must already be initialised + and running at the desired sampling frequency. + + Example reading 3 ADC's:: + + adc0 = pyb.ADC(pyb.Pin.board.X1) # Create ADC's + adc1 = pyb.ADC(pyb.Pin.board.X2) + adc2 = pyb.ADC(pyb.Pin.board.X3) + tim = pyb.Timer(8, freq=100) # Create timer + rx0 = array.array('H', (0 for i in range(100))) # ADC buffers of + rx1 = array.array('H', (0 for i in range(100))) # 100 16-bit words + rx2 = array.array('H', (0 for i in range(100))) + # read analog values into buffers at 100Hz (takes one second) + pyb.ADC.read_timed_multi((adc0, adc1, adc2), (rx0, rx1, rx2), tim) + for n in range(len(rx0)): + print(rx0[n], rx1[n], rx2[n]) + + This function does not allocate any heap memory. It has blocking behaviour: + it does not return to the calling program until the buffers are full. + + The function returns ``True`` if all samples were acquired with correct + timing. At high sample rates the time taken to acquire a set of samples + can exceed the timer period. In this case the function returns ``False``, + indicating a loss of precision in the sample interval. In extreme cases + samples may be missed. + + The maximum rate depends on factors including the data width and the + number of ADC's being read. In testing two ADC's were sampled at a timer + rate of 140KHz without overrun. Samples were missed at 180KHz. At high + sample rates disabling interrupts for the duration can reduce the risk + of sporadic data loss. The ADCAll Object ----------------- diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 3f00ad875..ba1ca5ce5 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -450,9 +450,116 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ } STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed); +// read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer) +// +// Read analog values from multiple ADC's into buffers at a rate set by the +// timer. The ADC values have 12-bit resolution and are stored directly into +// the corresponding buffer if its element size is 16 bits or greater, otherwise +// the sample resolution will be reduced to 8 bits. +// +// This function should not allocate any heap memory. +STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_in, mp_obj_t tim_in) { + size_t nadcs, nbufs; + mp_obj_t *adc_array, *buf_array; + mp_obj_get_array(adc_array_in, &nadcs, &adc_array); + mp_obj_get_array(buf_array_in, &nbufs, &buf_array); + + if (nadcs < 1) { + mp_raise_ValueError("need at least 1 ADC"); + } + if (nadcs != nbufs) { + mp_raise_ValueError("length of ADC and buffer lists differ"); + } + + // Get buf for first ADC, get word size, check other buffers match in type + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_array[0], &bufinfo, MP_BUFFER_WRITE); + size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL); + for (uint array_index = 0; array_index < nbufs; array_index++) { + mp_buffer_info_t bufinfo_curr; + mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); + if ((bufinfo.len != bufinfo_curr.len) || (bufinfo.typecode != bufinfo_curr.typecode)) { + mp_raise_ValueError("size and type of buffers must match"); + } + } + + // Use the supplied timer object as the sampling time base + TIM_HandleTypeDef *tim; + tim = pyb_timer_get_handle(tim_in); + + // Start adc; this is slow so wait for it to start + pyb_obj_adc_t *adc0 = adc_array[0]; + adc_config_channel(&adc0->handle, adc0->channel); + HAL_ADC_Start(&adc0->handle); + // Wait for sample to complete and discard + #define READ_TIMED_TIMEOUT (10) // in ms + adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT); + // Read (and discard) value + uint value = ADCx->DR; + + // Ensure first sample is on a timer tick + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { + } + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + + // Overrun check: assume success + bool success = true; + size_t nelems = bufinfo.len / typesize; + for (size_t elem_index = 0; elem_index < nelems; elem_index++) { + if (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) != RESET) { + // Timer has already triggered + success = false; + } else { + // Wait for the timer to trigger so we sample at the correct frequency + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { + } + } + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); + + for (size_t array_index = 0; array_index < nadcs; array_index++) { + pyb_obj_adc_t *adc = adc_array[array_index]; + // configure the ADC channel + adc_config_channel(&adc->handle, adc->channel); + // for the first sample we need to turn the ADC on + // ADC is started: set the "start sample" bit + #if defined(STM32F4) || defined(STM32F7) + ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; + #elif defined(STM32L4) + SET_BIT(ADCx->CR, ADC_CR_ADSTART); + #else + #error Unsupported processor + #endif + // wait for sample to complete + #define READ_TIMED_TIMEOUT (10) // in ms + adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT); + + // read value + value = ADCx->DR; + + // store values in buffer + if (typesize == 1) { + value >>= 4; + } + mp_buffer_info_t bufinfo_curr; // Get buf for current ADC + mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); + mp_binary_set_val_array_from_int(bufinfo_curr.typecode, bufinfo_curr.buf, elem_index, value); + } + } + + // Turn the ADC off + adc0 = adc_array[0]; + HAL_ADC_Stop(&adc0->handle); + + return mp_obj_new_bool(success); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_multi_fun_obj, adc_read_timed_multi); +STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(adc_read_timed_multi_obj, MP_ROM_PTR(&adc_read_timed_multi_fun_obj)); + STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&adc_read_obj) }, { MP_ROM_QSTR(MP_QSTR_read_timed), MP_ROM_PTR(&adc_read_timed_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_timed_multi), MP_ROM_PTR(&adc_read_timed_multi_obj) }, }; STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table); diff --git a/tests/pyb/adc.py b/tests/pyb/adc.py index 7834c7520..0bd9b9d53 100644 --- a/tests/pyb/adc.py +++ b/tests/pyb/adc.py @@ -32,3 +32,31 @@ adcv.read_timed(arv, tim) print(len(arv)) for i in arv: assert i > 1000 and i < 2000 + +# Test read_timed_multi +arv = bytearray(b'\xff'*50) +art = bytearray(b'\xff'*50) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 60 and i < 125 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 15 and i < 200 + +arv = array.array('i', 25 * [-1]) +art = array.array('i', 25 * [-1]) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 1000 and i < 2000 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 50 and i < 2000 + +arv = array.array('h', 25 * [0x7fff]) +art = array.array('h', 25 * [0x7fff]) +ADC.read_timed_multi((adcv, adct), (arv, art), tim) +for i in arv: + assert i > 1000 and i < 2000 +# Wide range: unsure of accuracy of temp sensor. +for i in art: + assert i > 50 and i < 2000 -- cgit v1.2.3 From aebd9701a78d267cb264d400804b02c5b7a00e9a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 11 Apr 2018 14:08:23 +1000 Subject: stm32/adc: Optimise read_timed_multi() by caching buffer pointers. --- docs/library/pyb.ADC.rst | 7 ++++--- ports/stm32/adc.c | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'docs/library') diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index c2d09ad40..1256c6a3c 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -125,9 +125,10 @@ Methods The maximum rate depends on factors including the data width and the number of ADC's being read. In testing two ADC's were sampled at a timer - rate of 140KHz without overrun. Samples were missed at 180KHz. At high - sample rates disabling interrupts for the duration can reduce the risk - of sporadic data loss. + rate of 210kHz without overrun. Samples were missed at 215kHz. For three + ADC's the limit is around 140kHz, and for four it is around 110kHz. + At high sample rates disabling interrupts for the duration can reduce the + risk of sporadic data loss. The ADCAll Object ----------------- diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index ba1ca5ce5..f765870d5 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -475,12 +475,14 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_array[0], &bufinfo, MP_BUFFER_WRITE); size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL); + void *bufptrs[nbufs]; for (uint array_index = 0; array_index < nbufs; array_index++) { mp_buffer_info_t bufinfo_curr; mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); if ((bufinfo.len != bufinfo_curr.len) || (bufinfo.typecode != bufinfo_curr.typecode)) { mp_raise_ValueError("size and type of buffers must match"); } + bufptrs[array_index] = bufinfo_curr.buf; } // Use the supplied timer object as the sampling time base @@ -541,9 +543,7 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i if (typesize == 1) { value >>= 4; } - mp_buffer_info_t bufinfo_curr; // Get buf for current ADC - mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE); - mp_binary_set_val_array_from_int(bufinfo_curr.typecode, bufinfo_curr.buf, elem_index, value); + mp_binary_set_val_array_from_int(bufinfo.typecode, bufptrs[array_index], elem_index, value); } } -- cgit v1.2.3 From b30e0d2f2683a809ae393dd402aad89a62a22df3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 10 Apr 2018 22:25:55 +1000 Subject: stm32/dac: Add buffering argument to constructor and init() method. This can be used to select the output buffer behaviour of the DAC. The default values are chosen to retain backwards compatibility with existing behaviour. Thanks to @peterhinch for the initial idea to add this feature. --- docs/library/pyb.DAC.rst | 21 ++++++++++++++++++--- ports/stm32/dac.c | 24 ++++++++++++++++++++---- tests/pyb/dac.py | 4 ++++ 3 files changed, 42 insertions(+), 7 deletions(-) (limited to 'docs/library') diff --git a/docs/library/pyb.DAC.rst b/docs/library/pyb.DAC.rst index fd786b63b..3e236a3da 100644 --- a/docs/library/pyb.DAC.rst +++ b/docs/library/pyb.DAC.rst @@ -49,7 +49,7 @@ To output a continuous sine-wave at 12-bit resolution:: Constructors ------------ -.. class:: pyb.DAC(port, bits=8) +.. class:: pyb.DAC(port, bits=8, \*, buffering=None) Construct a new DAC object. @@ -60,12 +60,27 @@ Constructors The maximum value for the write and write_timed methods will be 2\*\*``bits``-1. + The *buffering* parameter selects the behaviour of the DAC op-amp output + buffer, whose purpose is to reduce the output impedance. It can be + ``None`` to select the default (buffering enabled for :meth:`DAC.noise`, + :meth:`DAC.triangle` and :meth:`DAC.write_timed`, and disabled for + :meth:`DAC.write`), ``False`` to disable buffering completely, or ``True`` + to enable output buffering. + + When buffering is enabled the DAC pin can drive loads down to 5KΩ. + Otherwise it has an output impedance of 15KΩ maximum: consequently + to achieve a 1% accuracy without buffering requires the applied load + to be less than 1.5MΩ. Using the buffer incurs a penalty in accuracy, + especially near the extremes of range. + Methods ------- -.. method:: DAC.init(bits=8) +.. method:: DAC.init(bits=8, \*, buffering=None) - Reinitialise the DAC. ``bits`` can be 8 or 12. + Reinitialise the DAC. *bits* can be 8 or 12. *buffering* can be + ``None``, ``False`` or ``True`; see above constructor for the meaning + of this parameter. .. method:: DAC.deinit() diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index bce30dbc7..04acfb8aa 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -143,11 +143,14 @@ typedef struct _pyb_dac_obj_t { uint16_t pin; // GPIO_PIN_4 or GPIO_PIN_5 uint8_t bits; // 8 or 12 uint8_t state; + uint8_t outbuf_single; + uint8_t outbuf_waveform; } pyb_dac_obj_t; STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_buffering, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, }; // parse args @@ -194,6 +197,19 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp mp_raise_ValueError("unsupported bits"); } + // set output buffer config + if (args[1].u_obj == mp_const_none) { + // due to legacy, default values differ for single and waveform outputs + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else if (mp_obj_is_true(args[1].u_obj)) { + self->outbuf_single = DAC_OUTPUTBUFFER_ENABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_ENABLE; + } else { + self->outbuf_single = DAC_OUTPUTBUFFER_DISABLE; + self->outbuf_waveform = DAC_OUTPUTBUFFER_DISABLE; + } + // reset state of DAC self->state = DAC_STATE_RESET; @@ -289,7 +305,7 @@ STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) { // configure DAC to trigger via TIM6 DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_BUILTIN_WAVEFORM; } @@ -319,7 +335,7 @@ STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { // configure DAC to trigger via TIM6 DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_BUILTIN_WAVEFORM; } @@ -342,7 +358,7 @@ STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) { if (self->state != DAC_STATE_WRITE_SINGLE) { DAC_ChannelConfTypeDef config; config.DAC_Trigger = DAC_TRIGGER_NONE; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE; + config.DAC_OutputBuffer = self->outbuf_single; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_WRITE_SINGLE; } @@ -454,7 +470,7 @@ mp_obj_t pyb_dac_write_timed(size_t n_args, const mp_obj_t *pos_args, mp_map_t * if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) { DAC_ChannelConfTypeDef config; config.DAC_Trigger = dac_trigger; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + config.DAC_OutputBuffer = self->outbuf_waveform; HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger; } diff --git a/tests/pyb/dac.py b/tests/pyb/dac.py index 6f03bbc64..ca68ec709 100644 --- a/tests/pyb/dac.py +++ b/tests/pyb/dac.py @@ -12,3 +12,7 @@ dac.write(0) dac.write_timed(bytearray(10), 100, mode=pyb.DAC.NORMAL) pyb.delay(20) dac.write(0) + +# test buffering arg +dac = pyb.DAC(1, buffering=True) +dac.write(0) -- cgit v1.2.3 From 06006459447c8e7eaa031058a83f54bb06891bcb Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Wed, 11 Apr 2018 09:14:05 +0100 Subject: docs/library/pyb.ADC: Remove outdated ADCAll code example. --- docs/library/pyb.ADC.rst | 45 ++++----------------------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) (limited to 'docs/library') diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 1256c6a3c..679ba2f5a 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -170,44 +170,7 @@ The ADCAll Object The default value is 0xffffffff which means all analog inputs are active. If just the internal channels (16..18) are required, the mask value should be 0x70000. - It is possible to access channle 16..18 values without incurring the side effects of ``ADCAll``:: - - def adcread(chan): # 16 temp 17 vbat 18 vref - assert chan >= 16 and chan <= 18, 'Invalid ADC channel' - start = pyb.millis() - timeout = 100 - stm.mem32[stm.RCC + stm.RCC_APB2ENR] |= 0x100 # enable ADC1 clock.0x4100 - stm.mem32[stm.ADC1 + stm.ADC_CR2] = 1 # Turn on ADC - stm.mem32[stm.ADC1 + stm.ADC_CR1] = 0 # 12 bit - if chan == 17: - stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x200000 # 15 cycles - stm.mem32[stm.ADC + 4] = 1 << 23 - elif chan == 18: - stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x1000000 - stm.mem32[stm.ADC + 4] = 0xc00000 - else: - stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x40000 - stm.mem32[stm.ADC + 4] = 1 << 23 - stm.mem32[stm.ADC1 + stm.ADC_SQR3] = chan - stm.mem32[stm.ADC1 + stm.ADC_CR2] = 1 | (1 << 30) | (1 << 10) # start conversion - while not stm.mem32[stm.ADC1 + stm.ADC_SR] & 2: # wait for EOC - if pyb.elapsed_millis(start) > timeout: - raise OSError('ADC timout') - data = stm.mem32[stm.ADC1 + stm.ADC_DR] # clear down EOC - stm.mem32[stm.ADC1 + stm.ADC_CR2] = 0 # Turn off ADC - return data - - def v33(): - return 4096 * 1.21 / adcread(17) - - def vbat(): - return 1.21 * 2 * adcread(18) / adcread(17) # 2:1 divider on Vbat channel - - def vref(): - return 3.3 * adcread(17) / 4096 - - def temperature(): - return 25 + 400 * (3.3 * adcread(16) / 4096 - 0.76) - - Note that this example is only valid for the F405 MCU and all values are not corrected by Vref and - factory calibration data. + Example:: + + adcall = pyb.ADCAll(12, 0x70000) # 12 bit resolution, internal channels + temp = adcall.read_core_temp() -- cgit v1.2.3 From c24b0a7f2b7c0c30ef5fde62342eab7c0931f400 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 20 Apr 2018 15:54:09 +1000 Subject: docs/library/pyb.ADC: Fix typo of "prarmeter". --- docs/library/pyb.ADC.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/library') diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 679ba2f5a..05aaa5015 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -165,7 +165,7 @@ The ADCAll Object Other analog input channels (0..15) will return unscaled integer values according to the selected precision. - To avoid unwanted activation of analog inputs (channel 0..15) a second prarmeter can be specified. + To avoid unwanted activation of analog inputs (channel 0..15) a second parameter can be specified. This parameter is a binary pattern where each requested analog input has the corresponding bit set. The default value is 0xffffffff which means all analog inputs are active. If just the internal channels (16..18) are required, the mask value should be 0x70000. -- cgit v1.2.3 From c7818032b160961bbd88a57926a78fcab297e4f2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 26 Apr 2018 17:14:51 +1000 Subject: docs/library: Add ussl module to library index for unix port. --- docs/library/index.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'docs/library') diff --git a/docs/library/index.rst b/docs/library/index.rst index af1a0ff69..d5678d37e 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -87,6 +87,7 @@ it will fallback to loading the built-in ``ujson`` module. ure.rst uselect.rst usocket.rst + ussl.rst ustruct.rst utime.rst uzlib.rst -- cgit v1.2.3 From 6c955932f3c4bfa56336cbacad389d9f874cba10 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 21 May 2018 14:08:37 +1000 Subject: stm32/rtc: Don't try to set SubSeconds value on RTC. The hardware doesn't allow it, instead the value is reset to 255 upon setting the other calendar/time values. --- docs/library/pyb.RTC.rst | 2 +- ports/stm32/rtc.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'docs/library') diff --git a/docs/library/pyb.RTC.rst b/docs/library/pyb.RTC.rst index 262855452..1a1df9095 100644 --- a/docs/library/pyb.RTC.rst +++ b/docs/library/pyb.RTC.rst @@ -31,7 +31,7 @@ Methods With no arguments, this method returns an 8-tuple with the current date and time. With 1 argument (being an 8-tuple) it sets the date - and time. + and time (and ``subseconds`` is reset to 255). .. only:: port_pyboard diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 744fbe8b9..413403712 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -529,7 +529,6 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) { time.Hours = mp_obj_get_int(items[4]); time.Minutes = mp_obj_get_int(items[5]); time.Seconds = mp_obj_get_int(items[6]); - time.SubSeconds = rtc_us_to_subsec(mp_obj_get_int(items[7])); time.TimeFormat = RTC_HOURFORMAT12_AM; time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; time.StoreOperation = RTC_STOREOPERATION_SET; -- cgit v1.2.3