Merge branch 'master' into pr3

This commit is contained in:
Peter D. Gray 2018-03-29 15:39:38 -04:00 committed by GitHub
commit b8a5167517
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
402 changed files with 10186 additions and 3516 deletions

2
.gitmodules vendored
View File

@ -7,7 +7,7 @@
url = https://github.com/atgreen/libffi
[submodule "lib/lwip"]
path = lib/lwip
url = http://git.savannah.gnu.org/r/lwip.git
url = https://git.savannah.gnu.org/r/lwip.git
[submodule "lib/berkeley-db-1.xx"]
path = lib/berkeley-db-1.xx
url = https://github.com/pfalcon/berkeley-db-1.xx

View File

@ -6,6 +6,8 @@ compiler:
cache:
directories:
- "${HOME}/persist"
env:
- MAKEOPTS="-j4"
before_script:
# Extra CPython versions
@ -26,44 +28,47 @@ before_script:
- python3 --version
script:
- make -C mpy-cross
- make -C ports/minimal CROSS=1 build/firmware.bin
- make ${MAKEOPTS} -C mpy-cross
- make ${MAKEOPTS} -C ports/minimal CROSS=1 build/firmware.bin
- ls -l ports/minimal/build/firmware.bin
- tools/check_code_size.sh
- mkdir -p ${HOME}/persist
# Save new firmware for reference, but only if building a main branch, not a pull request
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cp ports/minimal/build/firmware.bin ${HOME}/persist/; fi'
- make -C ports/unix deplibs
- make -C ports/unix
- make -C ports/unix nanbox
- make -C ports/bare-arm
- make -C ports/qemu-arm -f Makefile.test test
- make -C ports/stm32
- make -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1
- make -C ports/stm32 BOARD=STM32F769DISC
- make -C ports/stm32 BOARD=STM32L476DISC
- make -C ports/teensy
- make -C ports/cc3200 BTARGET=application BTYPE=release
- make -C ports/cc3200 BTARGET=bootloader BTYPE=release
- make -C ports/windows CROSS_COMPILE=i686-w64-mingw32-
- make ${MAKEOPTS} -C ports/unix deplibs
- make ${MAKEOPTS} -C ports/unix
- make ${MAKEOPTS} -C ports/unix nanbox
- make ${MAKEOPTS} -C ports/bare-arm
- make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test test
- make ${MAKEOPTS} -C ports/stm32
- make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1
- make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC
- make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC
- make ${MAKEOPTS} -C ports/teensy
- make ${MAKEOPTS} -C ports/cc3200 BTARGET=application BTYPE=release
- make ${MAKEOPTS} -C ports/cc3200 BTARGET=bootloader BTYPE=release
- make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32-
# run tests without coverage info
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests)
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests --emit native)
# run tests with coverage info
- make -C ports/unix coverage
- make ${MAKEOPTS} -C ports/unix coverage
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests)
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread)
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native)
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float)
# test when input script comes from stdin
- cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc'
# run coveralls coverage analysis (try to, even if some builds/tests failed)
- (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod)
# run tests on stackless build
- rm -rf ports/unix/build-coverage
- make -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1"
- make ${MAKEOPTS} -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1"
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests)
after_failure:

View File

@ -17,7 +17,8 @@ it. To make an input pin use::
>>> pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP)
You can either use PULL_UP or None for the input pull-mode. If it's
not specified then it defaults to None, which is no pull resistor.
not specified then it defaults to None, which is no pull resistor. GPIO16
has no pull-up mode.
You can read the value on the pin using::
>>> pin.value()

View File

@ -28,8 +28,8 @@ You can set the frequency and duty cycle using::
>>> pwm12.duty(512)
Note that the duty cycle is between 0 (all off) and 1023 (all on), with 512
being a 50% duty. If you print the PWM object then it will tell you its current
configuration::
being a 50% duty. Values beyond this min/max will be clipped. If you
print the PWM object then it will tell you its current configuration::
>>> pwm12
PWM(12, freq=500, duty=512)

View File

@ -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.

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -24,11 +24,11 @@ Constructors
.. class:: pyb.CAN(bus, ...)
Construct a CAN object on the given bus. ``bus`` can be 1-2, or 'YA' or 'YB'.
Construct a CAN object on the given bus. *bus* can be 1-2, or ``'YA'`` or ``'YB'``.
With no additional parameters, the CAN object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
See :meth:`CAN.init` for parameters of initialisation.
The physical pins of the CAN busses are:
@ -42,28 +42,31 @@ Class Methods
Reset and disable all filter banks and assign how many banks should be available for CAN(1).
STM32F405 has 28 filter banks that are shared between the two available CAN bus controllers.
This function configures how many filter banks should be assigned to each. ``nr`` is the number of banks
This function configures how many filter banks should be assigned to each. *nr* is the number of banks
that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2).
At boot, 14 banks are assigned to each controller.
Methods
-------
.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8)
.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8, auto_restart=False)
Initialise the CAN bus with the given parameters:
- ``mode`` is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK
- if ``extframe`` is True then the bus uses extended identifiers in the frames
- *mode* is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK
- if *extframe* is True then the bus uses extended identifiers in the frames
(29 bits); otherwise it uses standard 11 bit identifiers
- ``prescaler`` is used to set the duration of 1 time quanta; the time quanta
- *prescaler* is used to set the duration of 1 time quanta; the time quanta
will be the input clock (PCLK1, see :meth:`pyb.freq()`) divided by the prescaler
- ``sjw`` is the resynchronisation jump width in units of the time quanta;
- *sjw* is the resynchronisation jump width in units of the time quanta;
it can be 1, 2, 3, 4
- ``bs1`` defines the location of the sample point in units of the time quanta;
- *bs1* defines the location of the sample point in units of the time quanta;
it can be between 1 and 1024 inclusive
- ``bs2`` defines the location of the transmit point in units of the time quanta;
- *bs2* defines the location of the transmit point in units of the time quanta;
it can be between 1 and 16 inclusive
- *auto_restart* sets whether the controller will automatically try and restart
communications after entering the bus-off state; if this is disabled then
:meth:`~CAN.restart()` can be used to leave the bus-off state
The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN
prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1);
@ -85,17 +88,64 @@ Methods
Turn off the CAN bus.
.. method:: CAN.restart()
Force a software restart of the CAN controller without resetting its
configuration.
If the controller enters the bus-off state then it will no longer participate
in bus activity. If the controller is not configured to automatically restart
(see :meth:`~CAN.init()`) then this method can be used to trigger a restart,
and the controller will follow the CAN protocol to leave the bus-off state and
go into the error active state.
.. method:: CAN.state()
Return the state of the controller. The return value can be one of:
- ``CAN.STOPPED`` -- the controller is completely off and reset;
- ``CAN.ERROR_ACTIVE`` -- the controller is on and in the Error Active state
(both TEC and REC are less than 96);
- ``CAN.ERROR_WARNING`` -- the controller is on and in the Error Warning state
(at least one of TEC or REC is 96 or greater);
- ``CAN.ERROR_PASSIVE`` -- the controller is on and in the Error Passive state
(at least one of TEC or REC is 128 or greater);
- ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity
(TEC overflowed beyond 255).
.. method:: CAN.info([list])
Get information about the controller's error states and TX and RX buffers.
If *list* is provided then it should be a list object with at least 8 entries,
which will be filled in with the information. Otherwise a new list will be
created and filled in. In both cases the return value of the method is the
populated list.
The values in the list are:
- TEC value
- REC value
- number of times the controller enterted the Error Warning state (wrapped
around to 0 after 65535)
- number of times the controller enterted the Error Passive state (wrapped
around to 0 after 65535)
- number of times the controller enterted the Bus Off state (wrapped
around to 0 after 65535)
- number of pending TX messages
- number of pending RX messages on fifo 0
- number of pending RX messages on fifo 1
.. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr)
Configure a filter bank:
- ``bank`` is the filter bank that is to be configured.
- ``mode`` is the mode the filter should operate in.
- ``fifo`` is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter.
- ``params`` is an array of values the defines the filter. The contents of the array depends on the ``mode`` argument.
- *bank* is the filter bank that is to be configured.
- *mode* is the mode the filter should operate in.
- *fifo* is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter.
- *params* is an array of values the defines the filter. The contents of the array depends on the *mode* argument.
+-----------+---------------------------------------------------------+
|``mode`` |contents of parameter array |
|*mode* |contents of *params* array |
+===========+=========================================================+
|CAN.LIST16 |Four 16 bit ids that will be accepted |
+-----------+---------------------------------------------------------+
@ -110,13 +160,13 @@ Methods
|CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.|
+-----------+---------------------------------------------------------+
- ``rtr`` is an array of booleans that states if a filter should accept a
- *rtr* is an array of booleans that states if a filter should accept a
remote transmission request message. If this argument is not given
then it defaults to False for all entries. The length of the array
depends on the ``mode`` argument.
then it defaults to ``False`` for all entries. The length of the array
depends on the *mode* argument.
+-----------+----------------------+
|``mode`` |length of rtr array |
|*mode* |length of *rtr* array |
+===========+======================+
|CAN.LIST16 |4 |
+-----------+----------------------+
@ -131,18 +181,19 @@ Methods
Clear and disables a filter bank:
- ``bank`` is the filter bank that is to be cleared.
- *bank* is the filter bank that is to be cleared.
.. method:: CAN.any(fifo)
Return ``True`` if any message waiting on the FIFO, else ``False``.
.. method:: CAN.recv(fifo, \*, timeout=5000)
.. method:: CAN.recv(fifo, list=None, \*, timeout=5000)
Receive data on the bus:
- ``fifo`` is an integer, which is the FIFO to receive on
- ``timeout`` is the timeout in milliseconds to wait for the receive.
- *fifo* is an integer, which is the FIFO to receive on
- *list* is an optional list object to be used as the return value
- *timeout* is the timeout in milliseconds to wait for the receive.
Return value: A tuple containing four values.
@ -151,17 +202,35 @@ Methods
- The FMI (Filter Match Index) value.
- An array containing the data.
If *list* is ``None`` then a new tuple will be allocated, as well as a new
bytes object to contain the data (as the fourth element in the tuple).
If *list* is not ``None`` then it should be a list object with a least four
elements. The fourth element should be a memoryview object which is created
from either a bytearray or an array of type 'B' or 'b', and this array must
have enough room for at least 8 bytes. The list object will then be
populated with the first three return values above, and the memoryview object
will be resized inplace to the size of the data and filled in with that data.
The same list and memoryview objects can be reused in subsequent calls to
this method, providing a way of receiving data without using the heap.
For example::
buf = bytearray(8)
lst = [0, 0, 0, memoryview(buf)]
# No heap memory is allocated in the following call
can.recv(0, lst)
.. method:: CAN.send(data, id, \*, timeout=0, rtr=False)
Send a message on the bus:
- ``data`` is the data to send (an integer to send, or a buffer object).
- ``id`` is the id of the message to be sent.
- ``timeout`` is the timeout in milliseconds to wait for the send.
- ``rtr`` is a boolean that specifies if the message shall be sent as
a remote transmission request. If ``rtr`` is True then only the length
of ``data`` is used to fill in the DLC slot of the frame; the actual
bytes in ``data`` are unused.
- *data* is the data to send (an integer to send, or a buffer object).
- *id* is the id of the message to be sent.
- *timeout* is the timeout in milliseconds to wait for the send.
- *rtr* is a boolean that specifies if the message shall be sent as
a remote transmission request. If *rtr* is True then only the length
of *data* is used to fill in the DLC slot of the frame; the actual
bytes in *data* are unused.
If timeout is 0 the message is placed in a buffer in one of three hardware
buffers and the method returns immediately. If all three buffers are in use
@ -175,8 +244,8 @@ Methods
Register a function to be called when a message is accepted into a empty fifo:
- ``fifo`` is the receiving fifo.
- ``fun`` is the function to be called when the fifo becomes non empty.
- *fifo* is the receiving fifo.
- *fun* is the function to be called when the fifo becomes non empty.
The callback function takes two arguments the first is the can object it self the second is
a integer that indicates the reason for the callback.
@ -209,15 +278,23 @@ Constants
---------
.. data:: CAN.NORMAL
.. data:: CAN.LOOPBACK
.. data:: CAN.SILENT
.. data:: CAN.SILENT_LOOPBACK
CAN.LOOPBACK
CAN.SILENT
CAN.SILENT_LOOPBACK
the mode of the CAN bus
The mode of the CAN bus used in :meth:`~CAN.init()`.
.. data:: CAN.STOPPED
CAN.ERROR_ACTIVE
CAN.ERROR_WARNING
CAN.ERROR_PASSIVE
CAN.BUS_OFF
Possible states of the CAN controller returned from :meth:`~CAN.state()`.
.. data:: CAN.LIST16
.. data:: CAN.MASK16
.. data:: CAN.LIST32
.. data:: CAN.MASK32
CAN.MASK16
CAN.LIST32
CAN.MASK32
the operation mode of a filter
The operation mode of a filter used in :meth:`~CAN.setfilter()`.

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -12,11 +12,24 @@ data format.
Functions
---------
.. function:: dump(obj, stream)
Serialise *obj* to a JSON string, writing it to the given *stream*.
.. function:: dumps(obj)
Return ``obj`` represented as a JSON string.
Return *obj* represented as a JSON string.
.. function:: load(stream)
Parse the given *stream*, interpreting it as a JSON string and
deserialising the data to a Python object. The resulting object is
returned.
Parsing continues until end-of-file is encountered.
A :exc:`ValueError` is raised if the data in *stream* is not correctly formed.
.. function:: loads(str)
Parse the JSON ``str`` and return an object. Raises ValueError if the
Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the
string is not correctly formed.

View File

@ -6,11 +6,32 @@
|see_cpython_module| :mod:`python:os`.
The ``uos`` module contains functions for filesystem access and ``urandom``
function.
The ``uos`` module contains functions for filesystem access and mounting,
terminal redirection and duplication, and the ``uname`` and ``urandom``
functions.
Functions
---------
General functions
-----------------
.. function:: uname()
Return a tuple (possibly a named tuple) containing information about the
underlying machine and/or its operating system. The tuple has five fields
in the following order, each of them being a string:
* ``sysname`` -- the name of the underlying system
* ``nodename`` -- the network name (can be the same as ``sysname``)
* ``release`` -- the version of the underlying system
* ``version`` -- the MicroPython version and build date
* ``machine`` -- an identifier for the underlying hardware (eg board, CPU)
.. function:: urandom(n)
Return a bytes object with *n* random bytes. Whenever possible, it is
generated by the hardware random number generator.
Filesystem access
-----------------
.. function:: chdir(path)
@ -22,11 +43,11 @@ Functions
.. function:: ilistdir([dir])
This function returns an iterator which then yields 3-tuples corresponding to
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The 3-tuples have the form *(name, type, inode)*:
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
@ -34,6 +55,10 @@ Functions
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
.. function:: listdir([dir])
@ -84,10 +109,8 @@ Functions
Sync all filesystems.
.. function:: urandom(n)
Return a bytes object with n random bytes. Whenever possible, it is
generated by the hardware random number generator.
Terminal redirection and duplication
------------------------------------
.. function:: dupterm(stream_object, index=0)
@ -108,3 +131,119 @@ Functions
the slot given by *index*.
The function returns the previous stream-like object in the given slot.
Filesystem mounting
-------------------
Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple
"real" filesystems within this VFS. Filesystem objects can be mounted at either
the root of the VFS, or at a subdirectory that lives in the root. This allows
dynamic and flexible configuration of the filesystem that is seen by Python
programs. Ports that have this functionality provide the :func:`mount` and
:func:`umount` functions, and possibly various filesystem implementations
represented by VFS classes.
.. function:: mount(fsobj, mount_point, \*, readonly)
Mount the filesystem object *fsobj* at the location in the VFS given by the
*mount_point* string. *fsobj* can be a a VFS object that has a ``mount()``
method, or a block device. If it's a block device then the filesystem type
is automatically detected (an exception is raised if no filesystem was
recognised). *mount_point* may be ``'/'`` to mount *fsobj* at the root,
or ``'/<name>'`` 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')

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -19,7 +19,7 @@ If your cursor is all the way back at the beginning, pressing RETURN will then
execute the code that you've entered. The following shows what you'd see
after entering a for statement (the underscore shows where the cursor winds up):
>>> for i in range(3):
>>> for i in range(30):
... _
If you then enter an if statement, an additional level of indentation will be
@ -58,9 +58,10 @@ Auto-completion
While typing a command at the REPL, if the line typed so far corresponds to
the beginning of the name of something, then pressing TAB will show
possible things that could be entered. For example type ``m`` and press TAB
and it should expand to ``machine``. Enter a dot ``.`` and press TAB again. You
should see something like:
possible things that could be entered. For example, first import the machine
module by entering ``import machine`` and pressing RETURN.
Then type ``m`` and press TAB and it should expand to ``machine``.
Enter a dot ``.`` and press TAB again. You should see something like:
>>> machine.
__name__ info unique_id reset
@ -151,7 +152,7 @@ method by which you're connected to the MicroPython board (USB-serial, or Wifi).
You can perform a soft reset from the REPL by pressing Ctrl-D, or from your python
code by executing: ::
raise SystemExit
machine.soft_reset()
For example, if you reset your MicroPython board, and you execute a dir()
command, you'd see something like this:

View File

@ -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.

57
drivers/bus/qspi.h Normal file
View File

@ -0,0 +1,57 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H
#define MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H
#include "py/mphal.h"
enum {
MP_QSPI_IOCTL_INIT,
MP_QSPI_IOCTL_DEINIT,
MP_QSPI_IOCTL_BUS_ACQUIRE,
MP_QSPI_IOCTL_BUS_RELEASE,
};
typedef struct _mp_qspi_proto_t {
int (*ioctl)(void *self, uint32_t cmd);
void (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data);
void (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src);
uint32_t (*read_cmd)(void *self, uint8_t cmd, size_t len);
void (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest);
} mp_qspi_proto_t;
typedef struct _mp_soft_qspi_obj_t {
mp_hal_pin_obj_t cs;
mp_hal_pin_obj_t clk;
mp_hal_pin_obj_t io0;
mp_hal_pin_obj_t io1;
mp_hal_pin_obj_t io2;
mp_hal_pin_obj_t io3;
} mp_soft_qspi_obj_t;
extern const mp_qspi_proto_t mp_soft_qspi_proto;
#endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H

203
drivers/bus/softqspi.c Normal file
View File

@ -0,0 +1,203 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "drivers/bus/qspi.h"
#define CS_LOW(self) mp_hal_pin_write(self->cs, 0)
#define CS_HIGH(self) mp_hal_pin_write(self->cs, 1)
#ifdef MICROPY_HW_SOFTQSPI_SCK_LOW
// Use externally provided functions for SCK control and IO reading
#define SCK_LOW(self) MICROPY_HW_SOFTQSPI_SCK_LOW(self)
#define SCK_HIGH(self) MICROPY_HW_SOFTQSPI_SCK_HIGH(self)
#define NIBBLE_READ(self) MICROPY_HW_SOFTQSPI_NIBBLE_READ(self)
#else
// Use generic pin functions for SCK control and IO reading
#define SCK_LOW(self) mp_hal_pin_write(self->clk, 0)
#define SCK_HIGH(self) mp_hal_pin_write(self->clk, 1)
#define NIBBLE_READ(self) ( \
mp_hal_pin_read(self->io0) \
| (mp_hal_pin_read(self->io1) << 1) \
| (mp_hal_pin_read(self->io2) << 2) \
| (mp_hal_pin_read(self->io3) << 3))
#endif
STATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) {
mp_hal_pin_write(self->io0, v & 1);
mp_hal_pin_write(self->io1, (v >> 1) & 1);
mp_hal_pin_write(self->io2, (v >> 2) & 1);
mp_hal_pin_write(self->io3, (v >> 3) & 1);
}
STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
switch (cmd) {
case MP_QSPI_IOCTL_INIT:
mp_hal_pin_high(self->cs);
mp_hal_pin_output(self->cs);
// Configure pins
mp_hal_pin_write(self->clk, 0);
mp_hal_pin_output(self->clk);
//mp_hal_pin_write(self->clk, 1);
mp_hal_pin_output(self->io0);
mp_hal_pin_input(self->io1);
mp_hal_pin_write(self->io2, 1);
mp_hal_pin_output(self->io2);
mp_hal_pin_write(self->io3, 1);
mp_hal_pin_output(self->io3);
break;
}
return 0; // success
}
STATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) {
// Will run as fast as possible, limited only by CPU speed and GPIO time
mp_hal_pin_input(self->io1);
mp_hal_pin_output(self->io0);
if (self->io3) {
mp_hal_pin_write(self->io2, 1);
mp_hal_pin_output(self->io2);
mp_hal_pin_write(self->io3, 1);
mp_hal_pin_output(self->io3);
}
if (src) {
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->io0, (data_out >> 7) & 1);
mp_hal_pin_write(self->clk, 1);
data_in = (data_in << 1) | mp_hal_pin_read(self->io1);
mp_hal_pin_write(self->clk, 0);
}
if (dest != NULL) {
dest[i] = data_in;
}
}
} else {
for (size_t i = 0; i < len; ++i) {
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j) {
mp_hal_pin_write(self->clk, 1);
data_in = (data_in << 1) | mp_hal_pin_read(self->io1);
mp_hal_pin_write(self->clk, 0);
}
if (dest != NULL) {
dest[i] = data_in;
}
}
}
}
STATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) {
// Make all IO lines input
mp_hal_pin_input(self->io2);
mp_hal_pin_input(self->io3);
mp_hal_pin_input(self->io0);
mp_hal_pin_input(self->io1);
// Will run as fast as possible, limited only by CPU speed and GPIO time
while (len--) {
SCK_HIGH(self);
uint8_t data_in = NIBBLE_READ(self);
SCK_LOW(self);
SCK_HIGH(self);
*buf++ = (data_in << 4) | NIBBLE_READ(self);
SCK_LOW(self);
}
}
STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) {
// Make all IO lines output
mp_hal_pin_output(self->io2);
mp_hal_pin_output(self->io3);
mp_hal_pin_output(self->io0);
mp_hal_pin_output(self->io1);
// Will run as fast as possible, limited only by CPU speed and GPIO time
for (size_t i = 0; i < len; ++i) {
nibble_write(self, buf[i] >> 4);
SCK_HIGH(self);
SCK_LOW(self);
nibble_write(self, buf[i]);
SCK_HIGH(self);
SCK_LOW(self);
}
//mp_hal_pin_input(self->io1);
}
STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint32_t cmd_buf = cmd | data << 8;
CS_LOW(self);
mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, NULL);
CS_HIGH(self);
}
STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint8_t cmd_buf[4] = {cmd, addr >> 16, addr >> 8, addr};
CS_LOW(self);
mp_soft_qspi_transfer(self, 4, cmd_buf, NULL);
mp_soft_qspi_transfer(self, len, src, NULL);
CS_HIGH(self);
}
STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint32_t cmd_buf = cmd;
CS_LOW(self);
mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf);
CS_HIGH(self);
return cmd_buf >> 8;
}
STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr};
CS_LOW(self);
mp_soft_qspi_transfer(self, 1, cmd_buf, NULL);
mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles)
mp_soft_qspi_qread(self, len, dest);
CS_HIGH(self);
}
const mp_qspi_proto_t mp_soft_qspi_proto = {
.ioctl = mp_soft_qspi_ioctl,
.write_cmd_data = mp_soft_qspi_write_cmd_data,
.write_cmd_addr_data = mp_soft_qspi_write_cmd_addr_data,
.read_cmd = mp_soft_qspi_read_cmd,
.read_cmd_qaddr_qdata = mp_soft_qspi_read_cmd_qaddr_qdata,
};

105
drivers/bus/softspi.c Normal file
View File

@ -0,0 +1,105 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "drivers/bus/spi.h"
int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) {
mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;
switch (cmd) {
case MP_SPI_IOCTL_INIT:
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_pin_output(self->sck);
mp_hal_pin_output(self->mosi);
mp_hal_pin_input(self->miso);
break;
case MP_SPI_IOCTL_DEINIT:
break;
}
return 0;
}
void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;
uint32_t delay_half = self->delay_half;
// only MSB transfer is implemented
// If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured
// delay_half is equal to this value, then the software SPI implementation
// will run as fast as possible, limited only by CPU speed and GPIO time.
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
mp_hal_pin_write(self->sck, 1 - self->polarity);
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
mp_hal_pin_write(self->sck, self->polarity);
}
if (dest != NULL) {
dest[i] = data_in;
}
}
return;
}
#endif
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
if (self->phase == 0) {
mp_hal_delay_us_fast(delay_half);
mp_hal_pin_write(self->sck, 1 - self->polarity);
} else {
mp_hal_pin_write(self->sck, 1 - self->polarity);
mp_hal_delay_us_fast(delay_half);
}
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
if (self->phase == 0) {
mp_hal_delay_us_fast(delay_half);
mp_hal_pin_write(self->sck, self->polarity);
} else {
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_delay_us_fast(delay_half);
}
}
if (dest != NULL) {
dest[i] = data_in;
}
}
}
const mp_spi_proto_t mp_soft_spi_proto = {
.ioctl = mp_soft_spi_ioctl,
.transfer = mp_soft_spi_transfer,
};

55
drivers/bus/spi.h Normal file
View File

@ -0,0 +1,55 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_DRIVERS_BUS_SPI_H
#define MICROPY_INCLUDED_DRIVERS_BUS_SPI_H
#include "py/mphal.h"
enum {
MP_SPI_IOCTL_INIT,
MP_SPI_IOCTL_DEINIT,
};
typedef struct _mp_spi_proto_t {
int (*ioctl)(void *self, uint32_t cmd);
void (*transfer)(void *self, size_t len, const uint8_t *src, uint8_t *dest);
} mp_spi_proto_t;
typedef struct _mp_soft_spi_obj_t {
uint32_t delay_half; // microsecond delay for half SCK period
uint8_t polarity;
uint8_t phase;
mp_hal_pin_obj_t sck;
mp_hal_pin_obj_t mosi;
mp_hal_pin_obj_t miso;
} mp_soft_spi_obj_t;
extern const mp_spi_proto_t mp_soft_spi_proto;
int mp_soft_spi_ioctl(void *self, uint32_t cmd);
void mp_soft_spi_transfer(void *self, size_t len, const uint8_t *src, uint8_t *dest);
#endif // MICROPY_INCLUDED_DRIVERS_BUS_SPI_H

View File

@ -50,7 +50,7 @@
#endif
// these need to be set to valid values before anything in this file will work
STATIC SPI_HandleTypeDef *SPI_HANDLE = NULL;
STATIC const spi_t *SPI_HANDLE = NULL;
STATIC const pin_obj_t *PIN_CS = NULL;
STATIC const pin_obj_t *PIN_EN = NULL;
STATIC const pin_obj_t *PIN_IRQ = NULL;
@ -134,17 +134,18 @@ void SpiOpen(gcSpiHandleRx pfRxHandler)
wlan_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER;
/* SPI configuration */
SPI_HANDLE->Init.Mode = SPI_MODE_MASTER;
SPI_HANDLE->Init.Direction = SPI_DIRECTION_2LINES;
SPI_HANDLE->Init.DataSize = SPI_DATASIZE_8BIT;
SPI_HANDLE->Init.CLKPolarity = SPI_POLARITY_LOW;
SPI_HANDLE->Init.CLKPhase = SPI_PHASE_2EDGE;
SPI_HANDLE->Init.NSS = SPI_NSS_SOFT;
SPI_HANDLE->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
SPI_HANDLE->Init.FirstBit = SPI_FIRSTBIT_MSB;
SPI_HANDLE->Init.TIMode = SPI_TIMODE_DISABLED;
SPI_HANDLE->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
SPI_HANDLE->Init.CRCPolynomial = 7;
SPI_InitTypeDef *init = &SPI_HANDLE->spi->Init;
init->Mode = SPI_MODE_MASTER;
init->Direction = SPI_DIRECTION_2LINES;
init->DataSize = SPI_DATASIZE_8BIT;
init->CLKPolarity = SPI_POLARITY_LOW;
init->CLKPhase = SPI_PHASE_2EDGE;
init->NSS = SPI_NSS_SOFT;
init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
init->FirstBit = SPI_FIRSTBIT_MSB;
init->TIMode = SPI_TIMODE_DISABLED;
init->CRCCalculation = SPI_CRCCALCULATION_DISABLED;
init->CRCPolynomial = 7;
spi_init(SPI_HANDLE, false);
// configure wlan CS and EN pins
@ -167,7 +168,7 @@ void SpiOpen(gcSpiHandleRx pfRxHandler)
actual communications start, it might be required */
CS_LOW();
uint8_t buf[1];
HAL_SPI_Receive(SPI_HANDLE, buf, sizeof(buf), SPI_TIMEOUT);
HAL_SPI_Receive(SPI_HANDLE->spi, buf, sizeof(buf), SPI_TIMEOUT);
CS_HIGH();
// register EXTI
@ -192,7 +193,7 @@ STATIC void SpiWriteDataSynchronous(unsigned char *data, unsigned short size)
{
DEBUG_printf("SpiWriteDataSynchronous(data=%p [%x %x %x %x], size=%u)\n", data, data[0], data[1], data[2], data[3], size);
__disable_irq();
if (HAL_SPI_TransmitReceive(SPI_HANDLE, data, data, size, SPI_TIMEOUT) != HAL_OK) {
if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) {
//BREAK();
}
__enable_irq();
@ -203,7 +204,7 @@ STATIC void SpiReadDataSynchronous(unsigned char *data, unsigned short size)
{
memset(data, READ, size);
__disable_irq();
if (HAL_SPI_TransmitReceive(SPI_HANDLE, data, data, size, SPI_TIMEOUT) != HAL_OK) {
if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) {
//BREAK();
}
__enable_irq();

35
drivers/dht/dht.py Normal file
View File

@ -0,0 +1,35 @@
# DHT11/DHT22 driver for MicroPython on ESP8266
# MIT license; Copyright (c) 2016 Damien P. George
try:
from esp import dht_readinto
except:
from pyb import dht_readinto
class DHTBase:
def __init__(self, pin):
self.pin = pin
self.buf = bytearray(5)
def measure(self):
buf = self.buf
dht_readinto(self.pin, buf)
if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]:
raise Exception("checksum error")
class DHT11(DHTBase):
def humidity(self):
return self.buf[0]
def temperature(self):
return self.buf[2]
class DHT22(DHTBase):
def humidity(self):
return (self.buf[0] << 8 | self.buf[1]) * 0.1
def temperature(self):
t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1
if self.buf[2] & 0x80:
t = -t
return t

View File

@ -32,7 +32,7 @@ class SSD1306(framebuf.FrameBuffer):
self.external_vcc = external_vcc
self.pages = self.height // 8
self.buffer = bytearray(self.pages * self.width)
super.__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
self.init_display()
def init_display(self):

View File

@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2016-2017 Damien P. George
* Copyright (c) 2016-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -29,57 +29,117 @@
#include "py/mperrno.h"
#include "py/mphal.h"
#include "extmod/machine_spi.h"
#include "drivers/memory/spiflash.h"
#define CMD_WRITE (0x02)
#define CMD_READ (0x03)
#define CMD_WRDI (0x04)
#define CMD_RDSR (0x05)
#define CMD_WREN (0x06)
#define CMD_SEC_ERASE (0x20)
#define QSPI_QE_MASK (0x02)
#define USE_WR_DELAY (1)
#define CMD_WRSR (0x01)
#define CMD_WRITE (0x02)
#define CMD_READ (0x03)
#define CMD_RDSR (0x05)
#define CMD_WREN (0x06)
#define CMD_SEC_ERASE (0x20)
#define CMD_RDCR (0x35)
#define CMD_RD_DEVID (0x9f)
#define CMD_CHIP_ERASE (0xc7)
#define CMD_C4READ (0xeb)
#define WAIT_SR_TIMEOUT (1000000)
#define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer
#define SECTOR_SIZE (4096) // size of erase sector
// Note: this code is not reentrant with this shared buffer
STATIC uint8_t buf[SECTOR_SIZE];
void mp_spiflash_init(mp_spiflash_t *self) {
mp_hal_pin_write(self->cs, 1);
mp_hal_pin_output(self->cs);
const mp_machine_spi_p_t *protocol = self->spi->type->protocol;
protocol->init(self->spi, 0, NULL, (mp_map_t*)&mp_const_empty_map);
}
STATIC uint8_t buf[SECTOR_SIZE] __attribute__((aligned(4)));
STATIC mp_spiflash_t *bufuser; // current user of buf
STATIC uint32_t bufsec; // current sector stored in buf; 0xffffffff if invalid
STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) {
// can be used for actions needed to acquire bus
(void)self;
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) {
c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_ACQUIRE);
}
}
STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) {
// can be used for actions needed to release bus
(void)self;
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) {
c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_RELEASE);
}
}
STATIC void mp_spiflash_transfer(mp_spiflash_t *self, size_t len, const uint8_t *src, uint8_t *dest) {
const mp_machine_spi_p_t *protocol = self->spi->type->protocol;
protocol->transfer(self->spi, len, src, dest);
STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t data) {
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
// Note: len/data are unused for standard SPI
mp_hal_pin_write(c->bus.u_spi.cs, 0);
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL);
mp_hal_pin_write(c->bus.u_spi.cs, 1);
} else {
c->bus.u_qspi.proto->write_cmd_data(c->bus.u_qspi.data, cmd, len, data);
}
}
STATIC void mp_spiflash_write_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
uint8_t buf[4] = {cmd, addr >> 16, addr >> 8, addr};
mp_hal_pin_write(c->bus.u_spi.cs, 0);
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL);
if (len) {
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, src, NULL);
}
mp_hal_pin_write(c->bus.u_spi.cs, 1);
} else {
c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src);
}
}
STATIC uint32_t mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len) {
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
uint32_t buf;
mp_hal_pin_write(c->bus.u_spi.cs, 0);
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL);
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, (void*)&buf, (void*)&buf);
mp_hal_pin_write(c->bus.u_spi.cs, 1);
return buf;
} else {
return c->bus.u_qspi.proto->read_cmd(c->bus.u_qspi.data, cmd, len);
}
}
STATIC void mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
uint8_t buf[4] = {CMD_READ, addr >> 16, addr >> 8, addr};
mp_hal_pin_write(c->bus.u_spi.cs, 0);
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL);
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, dest, dest);
mp_hal_pin_write(c->bus.u_spi.cs, 1);
} else {
c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, CMD_C4READ, addr, len, dest);
}
}
STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) {
mp_spiflash_write_cmd_data(self, cmd, 0, 0);
}
STATIC void mp_spiflash_write_cmd_addr(mp_spiflash_t *self, uint8_t cmd, uint32_t addr) {
mp_spiflash_write_cmd_addr_data(self, cmd, addr, 0, NULL);
}
STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) {
uint8_t cmd[1] = {CMD_RDSR};
mp_hal_pin_write(self->cs, 0);
mp_spiflash_transfer(self, 1, cmd, NULL);
uint8_t sr;
for (; timeout; --timeout) {
mp_spiflash_transfer(self, 1, cmd, cmd);
if ((cmd[0] & mask) == val) {
sr = mp_spiflash_read_cmd(self, CMD_RDSR, 1);
if ((sr & mask) == val) {
break;
}
}
mp_hal_pin_write(self->cs, 1);
if ((cmd[0] & mask) == val) {
if ((sr & mask) == val) {
return 0; // success
} else if (timeout == 0) {
return -MP_ETIMEDOUT;
@ -96,10 +156,40 @@ STATIC int mp_spiflash_wait_wip0(mp_spiflash_t *self) {
return mp_spiflash_wait_sr(self, 1, 0, WAIT_SR_TIMEOUT);
}
STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) {
mp_hal_pin_write(self->cs, 0);
mp_spiflash_transfer(self, 1, &cmd, NULL);
mp_hal_pin_write(self->cs, 1);
void mp_spiflash_init(mp_spiflash_t *self) {
self->flags = 0;
if (self->config->bus_kind == MP_SPIFLASH_BUS_SPI) {
mp_hal_pin_write(self->config->bus.u_spi.cs, 1);
mp_hal_pin_output(self->config->bus.u_spi.cs);
self->config->bus.u_spi.proto->ioctl(self->config->bus.u_spi.data, MP_SPI_IOCTL_INIT);
} else {
self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT);
}
mp_spiflash_acquire_bus(self);
#if defined(CHECK_DEVID)
// Validate device id
uint32_t devid = mp_spiflash_read_cmd(self, CMD_RD_DEVID, 3);
if (devid != CHECK_DEVID) {
return 0;
}
#endif
if (self->config->bus_kind == MP_SPIFLASH_BUS_QSPI) {
// Set QE bit
uint32_t data = (mp_spiflash_read_cmd(self, CMD_RDSR, 1) & 0xff)
| (mp_spiflash_read_cmd(self, CMD_RDCR, 1) & 0xff) << 8;
if (!(data & (QSPI_QE_MASK << 8))) {
data |= QSPI_QE_MASK << 8;
mp_spiflash_write_cmd(self, CMD_WREN);
mp_spiflash_write_cmd_data(self, CMD_WRSR, 2, data);
mp_spiflash_wait_wip0(self);
}
}
mp_spiflash_release_bus(self);
}
STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) {
@ -113,10 +203,7 @@ STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) {
}
// erase the sector
mp_hal_pin_write(self->cs, 0);
uint8_t cmd[4] = {CMD_SEC_ERASE, addr >> 16, addr >> 8, addr};
mp_spiflash_transfer(self, 4, cmd, NULL);
mp_hal_pin_write(self->cs, 1);
mp_spiflash_write_cmd_addr(self, CMD_SEC_ERASE, addr);
// wait WIP=0
return mp_spiflash_wait_wip0(self);
@ -133,67 +220,224 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint
}
// write the page
mp_hal_pin_write(self->cs, 0);
uint8_t cmd[4] = {CMD_WRITE, addr >> 16, addr >> 8, addr};
mp_spiflash_transfer(self, 4, cmd, NULL);
mp_spiflash_transfer(self, PAGE_SIZE, src, NULL);
mp_hal_pin_write(self->cs, 1);
mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, PAGE_SIZE, src);
// wait WIP=0
return mp_spiflash_wait_wip0(self);
}
void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
if (len == 0) {
return;
}
mp_spiflash_acquire_bus(self);
uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr};
mp_hal_pin_write(self->cs, 0);
mp_spiflash_transfer(self, 4, cmd, NULL);
mp_spiflash_transfer(self, len, dest, dest);
mp_hal_pin_write(self->cs, 1);
if (bufuser == self && bufsec != 0xffffffff) {
uint32_t bis = addr / SECTOR_SIZE;
uint32_t bie = (addr + len - 1) / SECTOR_SIZE;
if (bis <= bufsec && bufsec <= bie) {
// Read straddles current buffer
size_t rest = 0;
if (bis < bufsec) {
// Read direct from flash for first part
rest = bufsec * SECTOR_SIZE - addr;
mp_spiflash_read_data(self, addr, rest, dest);
len -= rest;
dest += rest;
addr += rest;
}
uint32_t offset = addr & (SECTOR_SIZE - 1);
rest = SECTOR_SIZE - offset;
if (rest > len) {
rest = len;
}
memcpy(dest, &buf[offset], rest);
len -= rest;
if (len == 0) {
mp_spiflash_release_bus(self);
return;
}
dest += rest;
addr += rest;
}
}
// Read rest direct from flash
mp_spiflash_read_data(self, addr, len, dest);
mp_spiflash_release_bus(self);
}
int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
// TODO optimise so we don't need to erase multiple times for successive writes to a sector
STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) {
#if USE_WR_DELAY
if (!(self->flags & 1)) {
return;
}
// align to 4096 sector
self->flags &= ~1;
// Erase sector
int ret = mp_spiflash_erase_sector(self, bufsec * SECTOR_SIZE);
if (ret != 0) {
return;
}
// Write
for (int i = 0; i < 16; i += 1) {
int ret = mp_spiflash_write_page(self, bufsec * SECTOR_SIZE + i * PAGE_SIZE, buf + i * PAGE_SIZE);
if (ret != 0) {
return;
}
}
#endif
}
void mp_spiflash_flush(mp_spiflash_t *self) {
mp_spiflash_acquire_bus(self);
mp_spiflash_flush_internal(self);
mp_spiflash_release_bus(self);
}
STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
// Align to 4096 sector
uint32_t offset = addr & 0xfff;
addr = (addr >> 12) << 12;
uint32_t sec = addr >> 12;
addr = sec << 12;
// restriction for now, so we don't need to erase multiple pages
// Restriction for now, so we don't need to erase multiple pages
if (offset + len > sizeof(buf)) {
printf("mp_spiflash_write: len is too large\n");
printf("mp_spiflash_write_part: len is too large\n");
return -MP_EIO;
}
mp_spiflash_acquire_bus(self);
// read sector
uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr};
mp_hal_pin_write(self->cs, 0);
mp_spiflash_transfer(self, 4, cmd, NULL);
mp_spiflash_transfer(self, SECTOR_SIZE, buf, buf);
mp_hal_pin_write(self->cs, 1);
// erase sector
int ret = mp_spiflash_erase_sector(self, addr);
if (ret != 0) {
mp_spiflash_release_bus(self);
return ret;
// Acquire the sector buffer
if (bufuser != self) {
if (bufuser != NULL) {
mp_spiflash_flush(bufuser);
}
bufuser = self;
bufsec = 0xffffffff;
}
// copy new block into buffer
if (bufsec != sec) {
// Read sector
#if USE_WR_DELAY
if (bufsec != 0xffffffff) {
mp_spiflash_flush_internal(self);
}
#endif
mp_spiflash_read_data(self, addr, SECTOR_SIZE, buf);
}
#if USE_WR_DELAY
bufsec = sec;
// Just copy to buffer
memcpy(buf + offset, src, len);
// And mark dirty
self->flags |= 1;
#else
uint32_t dirty = 0;
for (size_t i = 0; i < len; ++i) {
if (buf[offset + i] != src[i]) {
if (buf[offset + i] != 0xff) {
// Erase sector
int ret = mp_spiflash_erase_sector(self, addr);
if (ret != 0) {
return ret;
}
dirty = 0xffff;
break;
} else {
dirty |= (1 << ((offset + i) >> 8));
}
}
}
bufsec = sec;
// Copy new block into buffer
memcpy(buf + offset, src, len);
// write sector in pages of 256 bytes
for (int i = 0; i < SECTOR_SIZE; i += 256) {
ret = mp_spiflash_write_page(self, addr + i, buf + i);
// Write sector in pages of 256 bytes
for (size_t i = 0; i < 16; ++i) {
if (dirty & (1 << i)) {
int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, buf + i * PAGE_SIZE);
if (ret != 0) {
return ret;
}
}
}
#endif
return 0; // success
}
int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
uint32_t bis = addr / SECTOR_SIZE;
uint32_t bie = (addr + len - 1) / SECTOR_SIZE;
mp_spiflash_acquire_bus(self);
if (bufuser == self && bis <= bufsec && bie >= bufsec) {
// Write straddles current buffer
uint32_t pre;
uint32_t offset;
if (bufsec * SECTOR_SIZE >= addr) {
pre = bufsec * SECTOR_SIZE - addr;
offset = 0;
} else {
pre = 0;
offset = addr - bufsec * SECTOR_SIZE;
}
// Write buffered part first
uint32_t len_in_buf = len - pre;
len = 0;
if (len_in_buf > SECTOR_SIZE - offset) {
len = len_in_buf - (SECTOR_SIZE - offset);
len_in_buf = SECTOR_SIZE - offset;
}
memcpy(&buf[offset], &src[pre], len_in_buf);
self->flags |= 1; // Mark dirty
// Write part before buffer sector
while (pre) {
int rest = pre & (SECTOR_SIZE - 1);
if (rest == 0) {
rest = SECTOR_SIZE;
}
int ret = mp_spiflash_write_part(self, addr, rest, src);
if (ret != 0) {
mp_spiflash_release_bus(self);
return ret;
}
src += rest;
addr += rest;
pre -= rest;
}
src += len_in_buf;
addr += len_in_buf;
// Fall through to write remaining part
}
uint32_t offset = addr & (SECTOR_SIZE - 1);
while (len) {
int rest = SECTOR_SIZE - offset;
if (rest > len) {
rest = len;
}
int ret = mp_spiflash_write_part(self, addr, rest, src);
if (ret != 0) {
mp_spiflash_release_bus(self);
return ret;
}
len -= rest;
addr += rest;
src += rest;
offset = 0;
}
mp_spiflash_release_bus(self);
return 0; // success
return 0;
}

View File

@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Damien P. George
* Copyright (c) 2016-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -26,14 +26,36 @@
#ifndef MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H
#define MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H
#include "extmod/machine_spi.h"
#include "drivers/bus/spi.h"
#include "drivers/bus/qspi.h"
enum {
MP_SPIFLASH_BUS_SPI,
MP_SPIFLASH_BUS_QSPI,
};
typedef struct _mp_spiflash_config_t {
uint32_t bus_kind;
union {
struct {
mp_hal_pin_obj_t cs;
void *data;
const mp_spi_proto_t *proto;
} u_spi;
struct {
void *data;
const mp_qspi_proto_t *proto;
} u_qspi;
} bus;
} mp_spiflash_config_t;
typedef struct _mp_spiflash_t {
mp_hal_pin_obj_t cs;
mp_obj_base_t *spi; // object must have protocol pointing to mp_machine_spi_p_t struct
const mp_spiflash_config_t *config;
volatile uint32_t flags;
} mp_spiflash_t;
void mp_spiflash_init(mp_spiflash_t *self);
void mp_spiflash_flush(mp_spiflash_t *self);
void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest);
int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src);

View File

@ -14,10 +14,9 @@ Example usage on pyboard:
Example usage on ESP8266:
import machine, sdcard, os
sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15))
os.umount()
os.VfsFat(sd, "")
os.listdir()
sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15))
os.mount(sd, '/sd')
os.listdir('/')
"""
@ -46,6 +45,7 @@ class SDCard:
self.cmdbuf = bytearray(6)
self.dummybuf = bytearray(512)
self.tokenbuf = bytearray(1)
for i in range(512):
self.dummybuf[i] = 0xff
self.dummybuf_memoryview = memoryview(self.dummybuf)
@ -96,9 +96,14 @@ class SDCard:
raise OSError("no response from SD card")
csd = bytearray(16)
self.readinto(csd)
if csd[0] & 0xc0 != 0x40:
if csd[0] & 0xc0 == 0x40: # CSD version 2.0
self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014
elif csd[0] & 0xc0 == 0x00: # CSD version 1.0 (old, <=2GB)
c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4
c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7
self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2))
else:
raise OSError("SD card CSD format not supported")
self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014
#print('sectors', self.sectors)
# CMD16: set block length to 512 bytes
@ -129,7 +134,7 @@ class SDCard:
return
raise OSError("timeout waiting for v2 card")
def cmd(self, cmd, arg, crc, final=0, release=True):
def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
self.cs(0)
# create and send the command
@ -142,9 +147,13 @@ class SDCard:
buf[5] = crc
self.spi.write(buf)
if skip1:
self.spi.readinto(self.tokenbuf, 0xff)
# wait for the response (response[7] == 0)
for i in range(_CMD_TIMEOUT):
response = self.spi.read(1, 0xff)[0]
self.spi.readinto(self.tokenbuf, 0xff)
response = self.tokenbuf[0]
if not (response & 0x80):
# this could be a big-endian integer that we are getting here
for j in range(final):
@ -159,27 +168,19 @@ class SDCard:
self.spi.write(b'\xff')
return -1
def cmd_nodata(self, cmd):
self.spi.write(cmd)
self.spi.read(1, 0xff) # ignore stuff byte
for _ in range(_CMD_TIMEOUT):
if self.spi.read(1, 0xff)[0] == 0xff:
self.cs(1)
self.spi.write(b'\xff')
return 0 # OK
self.cs(1)
self.spi.write(b'\xff')
return 1 # timeout
def readinto(self, buf):
self.cs(0)
# read until start byte (0xff)
while self.spi.read(1, 0xff)[0] != 0xfe:
pass
while True:
self.spi.readinto(self.tokenbuf, 0xff)
if self.tokenbuf[0] == 0xfe:
break
# read data
mv = self.dummybuf_memoryview[:len(buf)]
mv = self.dummybuf_memoryview
if len(buf) != len(mv):
mv = mv[:len(buf)]
self.spi.write_readinto(mv, buf)
# read checksum
@ -226,26 +227,26 @@ class SDCard:
return self.sectors
def readblocks(self, block_num, buf):
nblocks, err = divmod(len(buf), 512)
assert nblocks and not err, 'Buffer length is invalid'
nblocks = len(buf) // 512
assert nblocks and not len(buf) % 512, 'Buffer length is invalid'
if nblocks == 1:
# CMD17: set read address for single block
if self.cmd(17, block_num * self.cdv, 0) != 0:
return 1
raise OSError(5) # EIO
# receive the data
self.readinto(buf)
else:
# CMD18: set read address for multiple blocks
if self.cmd(18, block_num * self.cdv, 0) != 0:
return 1
raise OSError(5) # EIO
offset = 0
mv = memoryview(buf)
while nblocks:
self.readinto(mv[offset : offset + 512])
offset += 512
nblocks -= 1
return self.cmd_nodata(b'\x0c') # cmd 12
return 0
if self.cmd(12, 0, 0xff, skip1=True):
raise OSError(5) # EIO
def writeblocks(self, block_num, buf):
nblocks, err = divmod(len(buf), 512)
@ -253,14 +254,14 @@ class SDCard:
if nblocks == 1:
# CMD24: set write address for single block
if self.cmd(24, block_num * self.cdv, 0) != 0:
return 1
raise OSError(5) # EIO
# send the data
self.write(_TOKEN_DATA, buf)
else:
# CMD25: set write address for first block
if self.cmd(25, block_num * self.cdv, 0) != 0:
return 1
raise OSError(5) # EIO
# send the data
offset = 0
mv = memoryview(buf)
@ -269,4 +270,3 @@ class SDCard:
offset += 512
nblocks -= 1
self.write_token(_TOKEN_STOP_TRAN)
return 0

View File

@ -13,7 +13,7 @@ include $(MPTOP)/py/py.mk
INC += -I.
INC += -I..
INC += -I$(MPTOP)
INC += -I$(MPTOP)/unix
INC += -I$(MPTOP)/ports/unix
INC += -I$(BUILD)
# compiler settings
@ -79,7 +79,7 @@ endif
endif
ifeq ($(MICROPY_USE_READLINE),1)
INC += -I../lib/mp-readline
INC += -I$(MPTOP)/lib/mp-readline
CFLAGS_MOD += -DMICROPY_USE_READLINE=1
LIB_SRC_C_EXTRA += mp-readline/readline.c
endif
@ -105,11 +105,11 @@ endif
ifeq ($(MICROPY_PY_FFI),1)
ifeq ($(MICROPY_STANDALONE),1)
LIBFFI_CFLAGS_MOD := -I$(shell ls -1d ../lib/libffi/build_dir/out/lib/libffi-*/include)
LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(MPTOP)/lib/libffi/build_dir/out/lib/libffi-*/include)
ifeq ($(MICROPY_FORCE_32BIT),1)
LIBFFI_LDFLAGS_MOD = ../lib/libffi/build_dir/out/lib32/libffi.a
LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib32/libffi.a
else
LIBFFI_LDFLAGS_MOD = ../lib/libffi/build_dir/out/lib/libffi.a
LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib/libffi.a
endif
else
LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi)
@ -128,7 +128,7 @@ endif
MAIN_C = main.c
# source files
SRC_C = $(addprefix $(MPTOP)/unix/,\
SRC_C = $(addprefix ports/unix/,\
$(MAIN_C) \
gccollect.c \
unix_mphal.c \
@ -159,7 +159,6 @@ endif
OBJ = $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(STMHAL_SRC_C:.c=.o))
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(LIB_SRC_C)
@ -182,18 +181,18 @@ deplibs: libffi axtls
# install-exec-recursive & install-data-am targets are used to avoid building
# docs and depending on makeinfo
libffi:
cd ../lib/libffi; git clean -d -x -f
cd ../lib/libffi; ./autogen.sh
mkdir -p ../lib/libffi/build_dir; cd ../lib/libffi/build_dir; \
cd $(MPTOP)/lib/libffi; git clean -d -x -f
cd $(MPTOP)/lib/libffi; ./autogen.sh
mkdir -p $(MPTOP)/lib/libffi/build_dir; cd $(MPTOP)/lib/libffi/build_dir; \
../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \
make install-exec-recursive; make -C include install-data-am
axtls: ../lib/axtls/README
cd ../lib/axtls; cp config/upyconfig config/.config
cd ../lib/axtls; make oldconfig -B
cd ../lib/axtls; make clean
cd ../lib/axtls; make all CC="$(CC)" LD="$(LD)"
axtls: $(MPTOP)/lib/axtls/README
cd $(MPTOP)/lib/axtls; cp config/upyconfig config/.config
cd $(MPTOP)/lib/axtls; make oldconfig -B
cd $(MPTOP)/lib/axtls; make clean
cd $(MPTOP)/lib/axtls; make all CC="$(CC)" LD="$(LD)"
../lib/axtls/README:
$(MPTOP)/lib/axtls/README:
@echo "You cloned without --recursive, fetching submodules for you."
(cd ..; git submodule update --init --recursive)
(cd $(MPTOP); git submodule update --init --recursive)

View File

@ -38,61 +38,6 @@
#define MICROPY_PY_MACHINE_SPI_LSB (1)
#endif
void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;
uint32_t delay_half = self->delay_half;
// only MSB transfer is implemented
// If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured
// delay_half is equal to this value, then the software SPI implementation
// will run as fast as possible, limited only by CPU speed and GPIO time.
#ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
mp_hal_pin_write(self->sck, 1 - self->polarity);
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
mp_hal_pin_write(self->sck, self->polarity);
}
if (dest != NULL) {
dest[i] = data_in;
}
}
return;
}
#endif
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
if (self->phase == 0) {
mp_hal_delay_us_fast(delay_half);
mp_hal_pin_write(self->sck, 1 - self->polarity);
} else {
mp_hal_pin_write(self->sck, 1 - self->polarity);
mp_hal_delay_us_fast(delay_half);
}
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
if (self->phase == 0) {
mp_hal_delay_us_fast(delay_half);
mp_hal_pin_write(self->sck, self->polarity);
} else {
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_delay_us_fast(delay_half);
}
}
if (dest != NULL) {
dest[i] = data_in;
}
}
}
/******************************************************************************/
// MicroPython bindings for generic machine.SPI
@ -199,9 +144,9 @@ MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table);
// Implementation of soft SPI
STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
#ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
return MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE;
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
return MICROPY_HW_SOFTSPI_MAX_BAUDRATE;
} else
#endif
{
@ -210,9 +155,9 @@ STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
}
STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) {
#ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
if (baudrate >= MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE) {
return MICROPY_PY_MACHINE_SPI_MIN_DELAY;
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE) {
return MICROPY_HW_SOFTSPI_MIN_DELAY;
} else
#endif
{
@ -229,8 +174,8 @@ STATIC void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in,
mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u,"
" sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")",
baudrate_from_delay_half(self->delay_half), self->polarity, self->phase,
mp_hal_pin_name(self->sck), mp_hal_pin_name(self->mosi), mp_hal_pin_name(self->miso));
baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase,
mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso));
}
STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
@ -253,9 +198,9 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
self->base.type = &mp_machine_soft_spi_type;
// set parameters
self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
self->polarity = args[ARG_polarity].u_int;
self->phase = args[ARG_phase].u_int;
self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
self->spi.polarity = args[ARG_polarity].u_int;
self->spi.phase = args[ARG_phase].u_int;
if (args[ARG_bits].u_int != 8) {
mp_raise_ValueError("bits must be 8");
}
@ -267,15 +212,12 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
|| args[ARG_miso].u_obj == MP_OBJ_NULL) {
mp_raise_ValueError("must specify all of sck/mosi/miso");
}
self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
// configure pins
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_pin_output(self->sck);
mp_hal_pin_output(self->mosi);
mp_hal_pin_input(self->miso);
// configure bus
mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);
return MP_OBJ_FROM_PTR(self);
}
@ -296,32 +238,34 @@ STATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if (args[ARG_baudrate].u_int != -1) {
self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
}
if (args[ARG_polarity].u_int != -1) {
self->polarity = args[ARG_polarity].u_int;
self->spi.polarity = args[ARG_polarity].u_int;
}
if (args[ARG_phase].u_int != -1) {
self->phase = args[ARG_phase].u_int;
self->spi.phase = args[ARG_phase].u_int;
}
if (args[ARG_sck].u_obj != MP_OBJ_NULL) {
self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
}
if (args[ARG_mosi].u_obj != MP_OBJ_NULL) {
self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
}
if (args[ARG_miso].u_obj != MP_OBJ_NULL) {
self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
}
// configure pins
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_pin_output(self->sck);
mp_hal_pin_output(self->mosi);
mp_hal_pin_input(self->miso);
// configure bus
mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);
}
STATIC const mp_machine_spi_p_t mp_machine_soft_spi_p = {
STATIC void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;
mp_soft_spi_transfer(&self->spi, len, src, dest);
}
const mp_machine_spi_p_t mp_machine_soft_spi_p = {
.init = mp_machine_soft_spi_init,
.deinit = NULL,
.transfer = mp_machine_soft_spi_transfer,

View File

@ -28,6 +28,7 @@
#include "py/obj.h"
#include "py/mphal.h"
#include "drivers/bus/spi.h"
// SPI protocol
typedef struct _mp_machine_spi_p_t {
@ -38,19 +39,13 @@ typedef struct _mp_machine_spi_p_t {
typedef struct _mp_machine_soft_spi_obj_t {
mp_obj_base_t base;
uint32_t delay_half; // microsecond delay for half SCK period
uint8_t polarity;
uint8_t phase;
mp_hal_pin_obj_t sck;
mp_hal_pin_obj_t mosi;
mp_hal_pin_obj_t miso;
mp_soft_spi_obj_t spi;
} mp_machine_soft_spi_obj_t;
extern const mp_machine_spi_p_t mp_machine_soft_spi_p;
extern const mp_obj_type_t mp_machine_soft_spi_type;
extern const mp_obj_dict_t mp_machine_spi_locals_dict;
void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest);
mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);

View File

@ -34,6 +34,16 @@
#if MICROPY_PY_UJSON
STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) {
if (!MP_OBJ_IS_OBJ(stream)) {
mp_raise_TypeError(NULL);
}
mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor};
mp_obj_print_helper(&print, obj, PRINT_JSON);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump);
STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
vstr_t vstr;
mp_print_t print;
@ -283,6 +293,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads);
STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) },
{ MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_ujson_dump_obj) },
{ MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) },
{ MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) },
{ MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) },

View File

@ -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;
}

View File

@ -47,6 +47,20 @@
#define mp_obj_fat_vfs_t fs_user_mount_t
mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) {
FILINFO fno;
assert(vfs != NULL);
FRESULT res = f_stat(&vfs->fatfs, path, &fno);
if (res == FR_OK) {
if ((fno.fattrib & AM_DIR) != 0) {
return MP_IMPORT_STAT_DIR;
} else {
return MP_IMPORT_STAT_FILE;
}
}
return MP_IMPORT_STAT_NO_EXIST;
}
STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);
@ -107,7 +121,52 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs);
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mkfs_fun_obj));
STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self);
typedef struct _mp_vfs_fat_ilistdir_it_t {
mp_obj_base_t base;
mp_fun_1_t iternext;
bool is_str;
FF_DIR dir;
} mp_vfs_fat_ilistdir_it_t;
STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) {
mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
for (;;) {
FILINFO fno;
FRESULT res = f_readdir(&self->dir, &fno);
char *fn = fno.fname;
if (res != FR_OK || fn[0] == 0) {
// stop on error or end of dir
break;
}
// Note that FatFS already filters . and .., so we don't need to
// make 4-tuple with info about this entry
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
if (self->is_str) {
t->items[0] = mp_obj_new_str(fn, strlen(fn));
} else {
t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));
}
if (fno.fattrib & AM_DIR) {
// dir
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
} else {
// file
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
}
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
t->items[3] = mp_obj_new_int_from_uint(fno.fsize);
return MP_OBJ_FROM_PTR(t);
}
// ignore error because we may be closing a second time
f_closedir(&self->dir);
return MP_OBJ_STOP_ITERATION;
}
STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) {
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]);
@ -122,7 +181,17 @@ STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) {
path = "";
}
return fat_vfs_ilistdir2(self, path, is_str_type);
// Create a new iterator object to list the dir
mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t);
iter->base.type = &mp_type_polymorph_iter;
iter->iternext = mp_vfs_fat_ilistdir_it_iternext;
iter->is_str = is_str_type;
FRESULT res = f_opendir(&self->fatfs, &iter->dir, path);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
return MP_OBJ_FROM_PTR(iter);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_ilistdir_obj, 1, 2, fat_vfs_ilistdir_func);

View File

@ -57,9 +57,6 @@ extern const byte fresult_to_errno_table[20];
extern const mp_obj_type_t mp_fat_vfs_type;
mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *path);
mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode);
MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj);
mp_obj_t fat_vfs_ilistdir2(struct _fs_user_mount_t *vfs, const char *path, bool is_str_type);
MP_DECLARE_CONST_FUN_OBJ_3(fat_vfs_open_obj);
#endif // MICROPY_INCLUDED_EXTMOD_VFS_FAT_H

View File

@ -36,6 +36,8 @@
#include "py/mphal.h"
#include "py/runtime.h"
#include "py/binary.h"
#include "py/objarray.h"
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
#include "extmod/vfs_fat.h"
@ -126,8 +128,9 @@ DRESULT disk_read (
return RES_ERROR;
}
} else {
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff};
vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
vfs->readblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), buff);
vfs->readblocks[3] = MP_OBJ_FROM_PTR(&ar);
mp_call_method_n_kw(2, 0, vfs->readblocks);
// TODO handle error return
}
@ -162,8 +165,9 @@ DRESULT disk_write (
return RES_ERROR;
}
} else {
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff};
vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
vfs->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), (void*)buff);
vfs->writeblocks[3] = MP_OBJ_FROM_PTR(&ar);
mp_call_method_n_kw(2, 0, vfs->writeblocks);
// TODO handle error return
}

View File

@ -134,11 +134,7 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
break;
case 1: // SEEK_CUR
if (s->offset != 0) {
*errcode = MP_EOPNOTSUPP;
return MP_STREAM_ERROR;
}
// no-operation
f_lseek(&self->fp, f_tell(&self->fp) + s->offset);
break;
case 2: // SEEK_END
@ -286,7 +282,7 @@ const mp_obj_type_t mp_type_textio = {
};
// Factory function for I/O stream classes
mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) {
STATIC mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) {
// TODO: analyze buffering args and instantiate appropriate type
fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);
mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];
@ -295,5 +291,6 @@ mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode)
arg_vals[2].u_obj = mp_const_none;
return file_open(self, &mp_type_textio, arg_vals);
}
MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self);
#endif // MICROPY_VFS && MICROPY_VFS_FAT

View File

@ -1,108 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mpconfig.h"
#if MICROPY_VFS_FAT
#include <string.h>
#include "py/runtime.h"
#include "lib/oofatfs/ff.h"
#include "extmod/vfs_fat.h"
#include "py/lexer.h"
typedef struct _mp_vfs_fat_ilistdir_it_t {
mp_obj_base_t base;
mp_fun_1_t iternext;
bool is_str;
FF_DIR dir;
} mp_vfs_fat_ilistdir_it_t;
STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) {
mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
for (;;) {
FILINFO fno;
FRESULT res = f_readdir(&self->dir, &fno);
char *fn = fno.fname;
if (res != FR_OK || fn[0] == 0) {
// stop on error or end of dir
break;
}
// Note that FatFS already filters . and .., so we don't need to
// make 3-tuple with info about this entry
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
if (self->is_str) {
t->items[0] = mp_obj_new_str(fn, strlen(fn));
} else {
t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));
}
if (fno.fattrib & AM_DIR) {
// dir
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
} else {
// file
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
}
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
return MP_OBJ_FROM_PTR(t);
}
// ignore error because we may be closing a second time
f_closedir(&self->dir);
return MP_OBJ_STOP_ITERATION;
}
mp_obj_t fat_vfs_ilistdir2(fs_user_mount_t *vfs, const char *path, bool is_str_type) {
mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t);
iter->base.type = &mp_type_polymorph_iter;
iter->iternext = mp_vfs_fat_ilistdir_it_iternext;
iter->is_str = is_str_type;
FRESULT res = f_opendir(&vfs->fatfs, &iter->dir, path);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
return MP_OBJ_FROM_PTR(iter);
}
mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) {
FILINFO fno;
assert(vfs != NULL);
FRESULT res = f_stat(&vfs->fatfs, path, &fno);
if (res == FR_OK) {
if ((fno.fattrib & AM_DIR) != 0) {
return MP_IMPORT_STAT_DIR;
} else {
return MP_IMPORT_STAT_FILE;
}
}
return MP_IMPORT_STAT_NO_EXIST;
}
#endif // MICROPY_VFS_FAT

@ -1 +1 @@
Subproject commit d2bcfda543d3b99361e44112aca929225bdcc07f
Subproject commit 90b9961963b625db0f2aabfe8e5e508b1f4fb7f1

View File

@ -35,7 +35,7 @@
#include "py/gc.h"
#include "py/frozenmod.h"
#include "py/mphal.h"
#if defined(USE_DEVICE_MODE)
#if MICROPY_HW_ENABLE_USB
#include "irq.h"
#include "usb.h"
#endif
@ -406,7 +406,7 @@ friendly_repl_reset:
for (;;) {
input_restart:
#if defined(USE_DEVICE_MODE)
#if MICROPY_HW_ENABLE_USB
if (usb_vcp_is_enabled()) {
// If the user gets to here and interrupts are disabled then
// they'll never see the prompt, traceback etc. The USB REPL needs

View File

@ -26,6 +26,8 @@
#ifndef MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H
#define MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H
#include "py/obj.h"
typedef enum {
PYEXEC_MODE_RAW_REPL,
PYEXEC_MODE_FRIENDLY_REPL,

View File

@ -36,7 +36,7 @@ SRC_S = \
# startup_stm32f40xx.s \
gchelper.s \
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
all: $(BUILD)/firmware.elf

View File

@ -21,19 +21,23 @@ FLASH_FREQ ?= 40m
FLASH_SIZE ?= 4MB
CROSS_COMPILE ?= xtensa-esp32-elf-
ESPIDF_SUPHASH := 3ede9f011b50999b0560683f9419538c066dd09e
# paths to ESP IDF and its components
ifeq ($(ESPIDF),)
ifneq ($(IDF_PATH),)
ESPIDF = $(IDF_PATH)
else
$(error Please configure the ESPIDF variable)
$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.)
$(info See README.md for installation instructions.)
$(info Supported git hash: $(ESPIDF_SUPHASH))
$(error ESPIDF not set)
endif
endif
ESPCOMP = $(ESPIDF)/components
ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py
# verify the ESP IDF version
ESPIDF_SUPHASH := 2c95a77cf93781f296883d5dbafcdc18e4389656
ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H')
ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH))
$(info ** WARNING **)
@ -86,6 +90,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include
INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include
INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include
INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include
INC_ESPCOMP += -I$(ESPCOMP)/app_update/include
CFLAGS_BASE = -std=gnu99 -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H -DESP_PLATFORM
CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP)
@ -143,11 +148,13 @@ SRC_C = \
network_lan.c \
modsocket.c \
modesp.c \
modesp32.c \
moduhashlib.c \
espneopixel.c \
machine_hw_spi.c \
machine_wdt.c \
mpthreadport.c \
machine_rtc.c \
$(SRC_MOD)
EXTMOD_SRC_C = $(addprefix extmod/,\
@ -188,6 +195,7 @@ LIB_SRC_C += \
endif
DRIVERS_SRC_C = $(addprefix drivers/,\
bus/softspi.c \
dht/dht.c \
)
@ -247,6 +255,7 @@ ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\
dport_access.o \
wifi_init.o \
wifi_internal.o \
sleep_modes.o \
)
ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\
@ -329,9 +338,9 @@ ESPIDF_VFS_O = $(addprefix $(ESPCOMP)/vfs/,\
vfs.o \
)
ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/,\
library/cJSON.o \
port/cJSON_Utils.o \
ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/cJSON/,\
cJSON.o \
cJSON_Utils.o \
)
ESPIDF_LOG_O = $(addprefix $(ESPCOMP)/log/,\
@ -351,6 +360,10 @@ ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\
app_trace.o \
)
ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\
esp_ota_ops.o \
)
ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\
time.o \
syscalls.o \
@ -587,6 +600,7 @@ OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_MBEDTLS_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_XTENSA_DEBUG_MODULE_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_TCPIP_ADAPTER_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_TRACE_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_UPDATE_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O))
@ -664,6 +678,7 @@ $(BUILD)/%.o: %.cpp
$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/esp32 -Wno-error=format
BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\
bootloader_support/src/bootloader_clock.o \
bootloader_support/src/bootloader_flash.o \
bootloader_support/src/bootloader_random.o \
bootloader_support/src/bootloader_sha.o \

View File

@ -26,34 +26,28 @@ There are two main components that are needed to build the firmware:
different to the compiler used by the ESP8266)
- the Espressif IDF (IoT development framework, aka SDK)
Instructions for setting up both of these components are provided by the
ESP-IDF itself, which is found at https://github.com/espressif/esp-idf .
Follow the guide "Setting Up ESP-IDF", for Windows, Mac or Linux. You
only need to perform up to "Step 2" of the guide, by which stage you
should have installed the cross-compile and cloned the ESP-IDF repository.
The ESP-IDF changes quickly and MicroPython only supports a certain version. The
git hash of this version can be found by running `make` without a configured
`ESPIDF`. Then you can fetch only the given esp-idf using the following command:
$ git clone https://github.com/espressif/esp-idf.git
$ git checkout <Current supported ESP-IDF commit hash>
$ git submodule update --recursive
The binary toolchain (binutils, gcc, etc.) can be installed using the following
guides:
* [Linux installation](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
* [MacOS installation](https://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html)
* [Windows installation](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html)
If you are on a Windows machine then the
[Windows Subsystem for Linux](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide)
is the most efficient way to install the ESP32 toolchain and build the project.
If you use WSL then follow the
[Linux guidelines](http://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
[Linux guidelines](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
for the ESP-IDF instead of the Windows ones.
Be advised that the ESP-IDF is still undergoing changes and only some
versions are supported. To find which build is compatible refer to the line
in the makefile containing the following:
```
ESPIDF_SUPHASH := <Current supported ESP-IDF commit hash>
```
After finishing "Step 2" you can roll back your current build of
the ESP-IDF (and update the submodules accordingly) using:
```
$ git checkout <Current supported ESP-IDF commit hash>
$ git submodule update --recursive
```
Note that you will get a warning when building the code if the ESP-IDF
version is incorrect.
The Espressif ESP-IDF instructions above only install pyserial for Python 2,
so if you're running Python 3 or a non-system Python you'll also need to
install `pyserial` (or `esptool`) so that the Makefile can flash the board
@ -64,7 +58,13 @@ $ pip install pyserial
Once everything is set up you should have a functioning toolchain with
prefix xtensa-esp32-elf- (or otherwise if you configured it differently)
as well as a copy of the ESP-IDF repository.
as well as a copy of the ESP-IDF repository. You will need to update your `PATH`
environment variable to include the ESP32 toolchain. For example, you can issue
the following commands on (at least) Linux:
$ export PATH=$PATH:$HOME/esp/crosstool-NG/builds/xtensa-esp32-elf/bin
You cam put this command in your `.profile` or `.bash_login`.
You then need to set the `ESPIDF` environment/makefile variable to point to
the root of the ESP-IDF repository. You can set the variable in your PATH,

View File

@ -89,7 +89,6 @@ SECTIONS
*esp32/core_dump.o(.literal .text .literal.* .text.*)
*app_trace/*(.literal .text .literal.* .text.*)
*xtensa-debug-module/eri.o(.literal .text .literal.* .text.*)
*libphy.a:(.literal .text .literal.* .text.*)
*librtc.a:(.literal .text .literal.* .text.*)
*libsoc.a:(.literal .text .literal.* .text.*)
*libhal.a:(.literal .text .literal.* .text.*)
@ -196,6 +195,13 @@ SECTIONS
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
_thread_local_start = ABSOLUTE(.);
*(.tdata)
*(.tdata.*)
*(.tbss)
*(.tbss.*)
_thread_local_end = ABSOLUTE(.);
. = ALIGN(4);
} >drom0_0_seg
.flash.text :

View File

@ -35,6 +35,8 @@
#include "py/mphal.h"
#include "modmachine.h"
#include "extmod/virtpin.h"
#include "machine_rtc.h"
#include "modesp32.h"
typedef struct _machine_pin_obj_t {
mp_obj_base_t base;
@ -219,10 +221,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_
// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING)
STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_handler, ARG_trigger, ARG_hard };
enum { ARG_handler, ARG_trigger, ARG_wake };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} },
{ MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@ -232,14 +235,48 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_
// configure irq
mp_obj_t handler = args[ARG_handler].u_obj;
uint32_t trigger = args[ARG_trigger].u_int;
if (handler == mp_const_none) {
handler = MP_OBJ_NULL;
trigger = 0;
mp_obj_t wake_obj = args[ARG_wake].u_obj;
if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) {
mp_int_t wake;
if (mp_obj_get_int_maybe(wake_obj, &wake)) {
if (wake < 2 || wake > 7) {
mp_raise_ValueError("bad wake value");
}
} else {
mp_raise_ValueError("bad wake value");
}
if (machine_rtc_config.wake_on_touch) { // not compatible
mp_raise_ValueError("no resources");
}
if (!RTC_IS_VALID_EXT_PIN(self->id)) {
mp_raise_ValueError("invalid pin for wake");
}
if (machine_rtc_config.ext0_pin == -1) {
machine_rtc_config.ext0_pin = self->id;
} else if (machine_rtc_config.ext0_pin != self->id) {
mp_raise_ValueError("no resources");
}
machine_rtc_config.ext0_level = trigger == GPIO_PIN_INTR_LOLEVEL ? 0 : 1;
machine_rtc_config.ext0_wake_types = wake;
} else {
if (machine_rtc_config.ext0_pin == self->id) {
machine_rtc_config.ext0_pin = -1;
}
if (handler == mp_const_none) {
handler = MP_OBJ_NULL;
trigger = 0;
}
gpio_isr_handler_remove(self->id);
MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler;
gpio_set_intr_type(self->id, trigger);
gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self);
}
gpio_isr_handler_remove(self->id);
MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler;
gpio_set_intr_type(self->id, trigger);
gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self);
}
// return the irq object
@ -261,6 +298,8 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN_ONLY) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) },
{ MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) },
{ MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) },
};
STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {

162
ports/esp32/machine_rtc.c Normal file
View File

@ -0,0 +1,162 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
* Copyright (c) 2017 "Tom Manning" <tom@manningetal.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "driver/gpio.h"
#include "py/nlr.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "timeutils.h"
#include "modmachine.h"
#include "machine_rtc.h"
typedef struct _machine_rtc_obj_t {
mp_obj_base_t base;
} machine_rtc_obj_t;
#define MEM_MAGIC 0x75507921
/* There is 8K of rtc_slow_memory, but some is used by the system software
If the USER_MAXLEN is set to high, the following compile error will happen:
region `rtc_slow_seg' overflowed by N bytes
The current system software allows almost 4096 to be used.
To avoid running into issues if the system software uses more, 2048 was picked as a max length
*/
#define MEM_USER_MAXLEN 2048
RTC_DATA_ATTR uint32_t rtc_user_mem_magic;
RTC_DATA_ATTR uint32_t rtc_user_mem_len;
RTC_DATA_ATTR uint8_t rtc_user_mem_data[MEM_USER_MAXLEN];
// singleton RTC object
STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}};
machine_rtc_config_t machine_rtc_config = {
.ext1_pins = 0,
.ext0_pin = -1
};
STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 0, 0, false);
// return constant object
return (mp_obj_t)&machine_rtc_obj;
}
STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// Get time
struct timeval tv;
gettimeofday(&tv, NULL);
timeutils_struct_time_t tm;
timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm);
mp_obj_t tuple[8] = {
mp_obj_new_int(tm.tm_year),
mp_obj_new_int(tm.tm_mon),
mp_obj_new_int(tm.tm_mday),
mp_obj_new_int(tm.tm_wday),
mp_obj_new_int(tm.tm_hour),
mp_obj_new_int(tm.tm_min),
mp_obj_new_int(tm.tm_sec),
mp_obj_new_int(tv.tv_usec)
};
return mp_obj_new_tuple(8, tuple);
} else {
// Set time
mp_obj_t *items;
mp_obj_get_array_fixed_n(args[1], 8, &items);
struct timeval tv = {0};
tv.tv_sec = timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6]));
settimeofday(&tv, NULL);
return mp_const_none;
}
}
STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
return machine_rtc_datetime_helper(n_args, args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);
STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) {
mp_obj_t args[2] = {self_in, date};
machine_rtc_datetime_helper(2, args);
if (rtc_user_mem_magic != MEM_MAGIC) {
rtc_user_mem_magic = MEM_MAGIC;
rtc_user_mem_len = 0;
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init);
STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// read RTC memory
uint32_t len = rtc_user_mem_len;
uint8_t rtcram[MEM_USER_MAXLEN];
memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len);
return mp_obj_new_bytes(rtcram, len);
} else {
// write RTC memory
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
if (bufinfo.len > MEM_USER_MAXLEN) {
mp_raise_ValueError("buffer too long");
}
memcpy( (char *) rtc_user_mem_data, (char *) bufinfo.buf, bufinfo.len);
rtc_user_mem_len = bufinfo.len;
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_memory_obj, 1, 2, machine_rtc_memory);
STATIC const mp_map_elem_t machine_rtc_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&machine_rtc_datetime_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&machine_rtc_datetime_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&machine_rtc_memory_obj },
};
STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table);
const mp_obj_type_t machine_rtc_type = {
{ &mp_type_type },
.name = MP_QSTR_RTC,
.make_new = machine_rtc_make_new,
.locals_dict = (mp_obj_t)&machine_rtc_locals_dict,
};

44
ports/esp32/machine_rtc.h Normal file
View File

@ -0,0 +1,44 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
* Copyright (c) 2017 "Tom Manning" <tom@manningetal.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ESP32_MACHINE_RTC_H
#define MICROPY_INCLUDED_ESP32_MACHINE_RTC_H
#include "modmachine.h"
typedef struct {
uint64_t ext1_pins; // set bit == pin#
int8_t ext0_pin; // just the pin#, -1 == None
bool wake_on_touch : 1;
bool ext0_level : 1;
wake_type_t ext0_wake_types;
bool ext1_level : 1;
} machine_rtc_config_t;
extern machine_rtc_config_t machine_rtc_config;
#endif

View File

@ -187,7 +187,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
// get uart id
mp_int_t uart_num = mp_obj_get_int(args[0]);
if (uart_num < 0 || uart_num > UART_NUM_MAX) {
if (uart_num < 0 || uart_num >= UART_NUM_MAX) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_num));
}
@ -297,7 +297,7 @@ STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t siz
int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait);
if (bytes_read < 0) {
if (bytes_read <= 0) {
*errcode = MP_EAGAIN;
return MP_STREAM_ERROR;
}

View File

@ -51,7 +51,7 @@ STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args
switch (id) {
case 0:
esp_task_wdt_feed();
esp_task_wdt_add(NULL);
return &wdt_default;
default:
mp_raise_ValueError(NULL);
@ -60,7 +60,7 @@ STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args
STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {
(void)self_in;
esp_task_wdt_feed();
esp_task_wdt_reset();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);

View File

@ -53,11 +53,9 @@
#define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1)
#define MP_TASK_STACK_SIZE (16 * 1024)
#define MP_TASK_STACK_LEN (MP_TASK_STACK_SIZE / sizeof(StackType_t))
#define MP_TASK_HEAP_SIZE (96 * 1024)
STATIC StaticTask_t mp_task_tcb;
STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8)));
STATIC uint8_t mp_task_heap[MP_TASK_HEAP_SIZE];
void mp_task(void *pvParameter) {
volatile uint32_t sp = (uint32_t)get_sp();
@ -66,11 +64,15 @@ void mp_task(void *pvParameter) {
#endif
uart_init();
// Allocate the uPy heap using malloc and get the largest available region
size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
void *mp_task_heap = malloc(mp_task_heap_size);
soft_reset:
// initialise the stack pointer for the main thread
mp_stack_set_top((void *)sp);
mp_stack_set_limit(MP_TASK_STACK_SIZE - 1024);
gc_init(mp_task_heap, mp_task_heap + sizeof(mp_task_heap));
gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size);
mp_init();
mp_obj_list_init(mp_sys_path, 0);
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));

138
ports/esp32/modesp32.c Normal file
View File

@ -0,0 +1,138 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "driver/gpio.h"
#include "py/nlr.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "timeutils.h"
#include "modmachine.h"
#include "machine_rtc.h"
#include "modesp32.h"
STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) {
if (machine_rtc_config.ext0_pin != -1) {
mp_raise_ValueError("no resources");
}
//nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "touchpad wakeup not available for this version of ESP-IDF"));
machine_rtc_config.wake_on_touch = mp_obj_is_true(wake);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_wake_on_touch_obj, esp32_wake_on_touch);
STATIC mp_obj_t esp32_wake_on_ext0(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
if (machine_rtc_config.wake_on_touch) {
mp_raise_ValueError("no resources");
}
enum {ARG_pin, ARG_level};
const mp_arg_t allowed_args[] = {
{ MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = mp_obj_new_int(machine_rtc_config.ext0_pin)} },
{ MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext0_level} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if (args[ARG_pin].u_obj == mp_const_none) {
machine_rtc_config.ext0_pin = -1; // "None"
} else {
gpio_num_t pin_id = machine_pin_get_id(args[ARG_pin].u_obj);
if (pin_id != machine_rtc_config.ext0_pin) {
if (!RTC_IS_VALID_EXT_PIN(pin_id)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin"));
}
machine_rtc_config.ext0_pin = pin_id;
}
}
machine_rtc_config.ext0_level = args[ARG_level].u_bool;
machine_rtc_config.ext0_wake_types = MACHINE_WAKE_SLEEP | MACHINE_WAKE_DEEPSLEEP;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext0_obj, 0, esp32_wake_on_ext0);
STATIC mp_obj_t esp32_wake_on_ext1(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum {ARG_pins, ARG_level};
const mp_arg_t allowed_args[] = {
{ MP_QSTR_pins, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_level, MP_ARG_BOOL, {.u_bool = machine_rtc_config.ext1_level} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
uint64_t ext1_pins = machine_rtc_config.ext1_pins;
// Check that all pins are allowed
if (args[ARG_pins].u_obj != mp_const_none) {
mp_uint_t len = 0;
mp_obj_t *elem;
mp_obj_get_array(args[ARG_pins].u_obj, &len, &elem);
ext1_pins = 0;
for (int i = 0; i < len; i++) {
gpio_num_t pin_id = machine_pin_get_id(elem[i]);
if (!RTC_IS_VALID_EXT_PIN(pin_id)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pin"));
break;
}
ext1_pins |= (1ll << pin_id);
}
}
machine_rtc_config.ext1_level = args[ARG_level].u_bool;
machine_rtc_config.ext1_pins = ext1_pins;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_wake_on_ext1_obj, 0, esp32_wake_on_ext1);
STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp32) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_touch), (mp_obj_t)&esp32_wake_on_touch_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext0), (mp_obj_t)&esp32_wake_on_ext0_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_on_ext1), (mp_obj_t)&esp32_wake_on_ext1_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ALL_LOW), mp_const_false },
{ MP_OBJ_NEW_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), mp_const_true },
};
STATIC MP_DEFINE_CONST_DICT(esp32_module_globals, esp32_module_globals_table);
const mp_obj_module_t esp32_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&esp32_module_globals,
};

29
ports/esp32/modesp32.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef MICROPY_INCLUDED_ESP32_MODESP32_H
#define MICROPY_INCLUDED_ESP32_MODESP32_H
#define RTC_VALID_EXT_PINS \
( \
(1ll << 0) | \
(1ll << 2) | \
(1ll << 4) | \
(1ll << 12) | \
(1ll << 13) | \
(1ll << 14) | \
(1ll << 15) | \
(1ll << 25) | \
(1ll << 26) | \
(1ll << 27) | \
(1ll << 32) | \
(1ll << 33) | \
(1ll << 34) | \
(1ll << 35) | \
(1ll << 36) | \
(1ll << 37) | \
(1ll << 38) | \
(1ll << 39) \
)
#define RTC_LAST_EXT_PIN 39
#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS)
#endif // MICROPY_INCLUDED_ESP32_MODESP32_H

View File

@ -33,7 +33,9 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "rom/ets_sys.h"
#include "rom/rtc.h"
#include "esp_system.h"
#include "driver/touch_pad.h"
#include "py/obj.h"
#include "py/runtime.h"
@ -43,9 +45,18 @@
#include "extmod/machine_i2c.h"
#include "extmod/machine_spi.h"
#include "modmachine.h"
#include "machine_rtc.h"
#if MICROPY_PY_MACHINE
typedef enum {
MP_PWRON_RESET = 1,
MP_HARD_RESET,
MP_WDT_RESET,
MP_DEEPSLEEP_RESET,
MP_SOFT_RESET
} reset_reason_t;
STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
// get
@ -64,6 +75,104 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq);
STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum {ARG_sleep_ms};
const mp_arg_t allowed_args[] = {
{ MP_QSTR_sleep_ms, MP_ARG_INT, { .u_int = 0 } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_int_t expiry = args[ARG_sleep_ms].u_int;
if (expiry != 0) {
esp_sleep_enable_timer_wakeup(expiry * 1000);
}
if (machine_rtc_config.ext0_pin != -1 && (machine_rtc_config.ext0_wake_types & wake_type)) {
esp_sleep_enable_ext0_wakeup(machine_rtc_config.ext0_pin, machine_rtc_config.ext0_level ? 1 : 0);
}
if (machine_rtc_config.ext1_pins != 0) {
esp_sleep_enable_ext1_wakeup(
machine_rtc_config.ext1_pins,
machine_rtc_config.ext1_level ? ESP_EXT1_WAKEUP_ANY_HIGH : ESP_EXT1_WAKEUP_ALL_LOW);
}
if (machine_rtc_config.wake_on_touch) {
if (esp_sleep_enable_touchpad_wakeup() != ESP_OK) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "esp_sleep_enable_touchpad_wakeup() failed"));
}
}
switch(wake_type) {
case MACHINE_WAKE_SLEEP:
esp_light_sleep_start();
break;
case MACHINE_WAKE_DEEPSLEEP:
esp_deep_sleep_start();
break;
}
return mp_const_none;
}
STATIC mp_obj_t machine_sleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "light sleep not available for this version of ESP-IDF"));
return machine_sleep_helper(MACHINE_WAKE_SLEEP, n_args, pos_args, kw_args);
};
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_sleep_obj, 0, machine_sleep);
STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return machine_sleep_helper(MACHINE_WAKE_DEEPSLEEP, n_args, pos_args, kw_args);
};
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_deepsleep_obj, 0, machine_deepsleep);
STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
switch(rtc_get_reset_reason(0)) {
case POWERON_RESET:
return MP_OBJ_NEW_SMALL_INT(MP_PWRON_RESET);
break;
case SW_RESET:
case SW_CPU_RESET:
return MP_OBJ_NEW_SMALL_INT(MP_SOFT_RESET);
break;
case OWDT_RESET:
case TG0WDT_SYS_RESET:
case TG1WDT_SYS_RESET:
case RTCWDT_SYS_RESET:
case RTCWDT_BROWN_OUT_RESET:
case RTCWDT_CPU_RESET:
case RTCWDT_RTC_RESET:
case TGWDT_CPU_RESET:
return MP_OBJ_NEW_SMALL_INT(MP_WDT_RESET);
break;
case DEEPSLEEP_RESET:
return MP_OBJ_NEW_SMALL_INT(MP_DEEPSLEEP_RESET);
break;
case EXT_CPU_RESET:
return MP_OBJ_NEW_SMALL_INT(MP_HARD_RESET);
break;
case NO_MEAN:
case SDIO_RESET:
case INTRUSION_RESET:
default:
return MP_OBJ_NEW_SMALL_INT(0);
break;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_reset_cause_obj, 0, machine_reset_cause);
STATIC mp_obj_t machine_wake_reason(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return MP_OBJ_NEW_SMALL_INT(esp_sleep_get_wakeup_cause());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_wake_reason_obj, 0, machine_wake_reason);
STATIC mp_obj_t machine_reset(void) {
esp_restart();
return mp_const_none;
@ -106,6 +215,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
{ MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
@ -115,6 +226,10 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) },
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) },
// wake abilities
{ MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(MACHINE_WAKE_SLEEP) },
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
{ MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) },
@ -122,8 +237,26 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) },
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
// Reset reasons
{ MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
{ MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(MP_HARD_RESET) },
{ MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) },
{ MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(MP_WDT_RESET) },
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(MP_DEEPSLEEP_RESET) },
{ MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(MP_SOFT_RESET) },
// Wake reasons
{ MP_ROM_QSTR(MP_QSTR_wake_reason), MP_ROM_PTR(&machine_wake_reason_obj) },
{ MP_ROM_QSTR(MP_QSTR_PIN_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) },
{ MP_ROM_QSTR(MP_QSTR_EXT0_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT0) },
{ MP_ROM_QSTR(MP_QSTR_EXT1_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_EXT1) },
{ MP_ROM_QSTR(MP_QSTR_TIMER_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TIMER) },
{ MP_ROM_QSTR(MP_QSTR_TOUCHPAD_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_TOUCHPAD) },
{ MP_ROM_QSTR(MP_QSTR_ULP_WAKE), MP_ROM_INT(ESP_SLEEP_WAKEUP_ULP) },
};
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);

View File

@ -3,6 +3,12 @@
#include "py/obj.h"
typedef enum {
//MACHINE_WAKE_IDLE=0x01,
MACHINE_WAKE_SLEEP=0x02,
MACHINE_WAKE_DEEPSLEEP=0x04
} wake_type_t;
extern const mp_obj_type_t machine_timer_type;
extern const mp_obj_type_t machine_wdt_type;
extern const mp_obj_type_t machine_pin_type;
@ -12,6 +18,7 @@ extern const mp_obj_type_t machine_dac_type;
extern const mp_obj_type_t machine_pwm_type;
extern const mp_obj_type_t machine_hw_spi_type;
extern const mp_obj_type_t machine_uart_type;
extern const mp_obj_type_t machine_rtc_type;
void machine_pins_init(void);
void machine_pins_deinit(void);

View File

@ -275,11 +275,36 @@ STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect);
STATIC mp_obj_t esp_status(mp_obj_t self_in) {
STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// no arguments: return None until link status is implemented
return mp_const_none;
}
// one argument: return status based on query parameter
switch ((uintptr_t)args[1]) {
case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): {
// return list of connected stations, only if in soft-AP mode
require_if(args[0], WIFI_IF_AP);
wifi_sta_list_t station_list;
ESP_EXCEPTIONS(esp_wifi_ap_get_sta_list(&station_list));
wifi_sta_info_t *stations = (wifi_sta_info_t*)station_list.sta;
mp_obj_t list = mp_obj_new_list(0, NULL);
for (int i = 0; i < station_list.num; ++i) {
mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL);
t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac));
mp_obj_list_append(list, t);
}
return list;
}
default:
mp_raise_ValueError("unknown status param");
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status);
STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
// check that STA mode is active
@ -445,6 +470,11 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
break;
}
case QS(MP_QSTR_dhcp_hostname): {
const char *s = mp_obj_str_get_str(kwargs->table[i].value);
ESP_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id, s));
break;
}
default:
goto unknown;
}
@ -494,6 +524,12 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
req_if = WIFI_IF_AP;
val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
break;
case QS(MP_QSTR_dhcp_hostname): {
const char *s;
ESP_EXCEPTIONS(tcpip_adapter_get_hostname(self->if_id, &s));
val = mp_obj_new_str(s, strlen(s));
break;
}
default:
goto unknown;
}

View File

@ -520,9 +520,11 @@ STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket);
STATIC mp_obj_t esp_socket_getaddrinfo(const mp_obj_t host, const mp_obj_t port) {
STATIC mp_obj_t esp_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) {
// TODO support additional args beyond the first two
struct addrinfo *res = NULL;
_socket_getaddrinfo2(host, port, &res);
_socket_getaddrinfo2(args[0], args[1], &res);
mp_obj_t ret_list = mp_obj_new_list(0, NULL);
for (struct addrinfo *resi = res; resi; resi = resi->ai_next) {
@ -552,7 +554,7 @@ STATIC mp_obj_t esp_socket_getaddrinfo(const mp_obj_t host, const mp_obj_t port)
if (res) lwip_freeaddrinfo(res);
return ret_list;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_getaddrinfo_obj, esp_socket_getaddrinfo);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_socket_getaddrinfo_obj, 2, 6, esp_socket_getaddrinfo);
STATIC mp_obj_t esp_socket_initialize() {
static int initialized = 0;

View File

@ -1 +1 @@
../../esp8266/modules/dht.py
../../../drivers/dht/dht.py

View File

@ -90,6 +90,7 @@
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_ATTRTUPLE (1)
#define MICROPY_PY_COLLECTIONS (1)
#define MICROPY_PY_COLLECTIONS_DEQUE (1)
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
#define MICROPY_PY_MATH (1)
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
@ -134,8 +135,8 @@
#define MICROPY_PY_MACHINE_SPI_MSB (0)
#define MICROPY_PY_MACHINE_SPI_LSB (1)
#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new
#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0)
#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly
#define MICROPY_HW_SOFTSPI_MIN_DELAY (0)
#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly
#define MICROPY_PY_USSL (1)
#define MICROPY_SSL_MBEDTLS (1)
#define MICROPY_PY_USSL_FINALISER (1)
@ -162,6 +163,7 @@
// extra built in modules to add to the list of known ones
extern const struct _mp_obj_module_t esp_module;
extern const struct _mp_obj_module_t esp32_module;
extern const struct _mp_obj_module_t utime_module;
extern const struct _mp_obj_module_t uos_module;
extern const struct _mp_obj_module_t mp_module_usocket;
@ -171,6 +173,7 @@ extern const struct _mp_obj_module_t mp_module_onewire;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_esp32), (mp_obj_t)&esp32_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \

View File

@ -1,3 +1,8 @@
/* Start bootloader config */
#define CONFIG_FLASHMODE_DIO 1
#define CONFIG_ESPTOOLPY_FLASHFREQ_40M 1
/* End bootloader config */
#define CONFIG_TRACEMEM_RESERVE_DRAM 0x0
#define CONFIG_BT_RESERVE_DRAM 0x0
#define CONFIG_ULP_COPROC_RESERVE_MEM 0
@ -23,7 +28,7 @@
#define CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240
#define CONFIG_ESP32_DEFAULT_CPU_FREQ_240 1
#define CONFIG_ESP32_DEBUG_OCDAWARE 1
#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 0
#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000
#define CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE 1
#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1
#define CONFIG_ESP32_WIFI_AMPDU_ENABLED 1
@ -104,6 +109,9 @@
#define CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX 0
#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1
#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1
#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60
#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8
#define CONFIG_LWIP_MAX_ACTIVE_TCP 16
#define CONFIG_LWIP_MAX_SOCKETS 8
#define CONFIG_LWIP_SO_REUSE 1
#define CONFIG_LWIP_ETHARP_TRUST_IP_MAC 1

View File

@ -130,6 +130,7 @@ LIB_SRC_C += \
endif
DRIVERS_SRC_C = $(addprefix drivers/,\
bus/softspi.c \
dht/dht.c \
)
@ -143,7 +144,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
#OBJ += $(BUILD)/pins_$(BOARD).o
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C)
@ -195,32 +195,6 @@ ota:
rm -f $(BUILD)/firmware.elf $(BUILD)/firmware.elf*.bin
$(MAKE) LDSCRIPT=esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin
#MAKE_PINS = boards/make-pins.py
#BOARD_PINS = boards/$(BOARD)/pins.csv
#AF_FILE = boards/stm32f4xx_af.csv
#PREFIX_FILE = boards/stm32f4xx_prefix.c
#GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c
#GEN_PINS_HDR = $(HEADER_BUILD)/pins.h
#GEN_PINS_QSTR = $(BUILD)/pins_qstr.h
#GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
#GEN_PINS_AF_PY = $(BUILD)/pins_af.py
# Making OBJ use an order-only depenedency on the generated pins.h file
# has the side effect of making the pins.h file before we actually compile
# any of the objects. The normal dependency generation will deal with the
# case when pins.h is modified. But when it doesn't exist, we don't know
# which source files might need it.
#$(OBJ): | $(HEADER_BUILD)/pins.h
# Use a pattern rule here so that make will only call make-pins.py once to make
# both pins_$(BOARD).c and pins.h
#$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
# $(ECHO) "Create $@"
# $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC)
#
#$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
# $(call compile_c)
include $(TOP)/py/mkrules.mk
axtls: $(BUILD)/libaxtls.a

View File

@ -49,7 +49,7 @@ $ make -C mpy-cross
Then, to build MicroPython for the ESP8266, just run:
```bash
$ cd esp8266
$ cd ports/esp8266
$ make axtls
$ make
```

View File

@ -135,6 +135,7 @@ SECTIONS
*lib/netutils/*.o*(.literal*, .text*)
*lib/timeutils/*.o*(.literal*, .text*)
*lib/utils/*.o*(.literal*, .text*)
*drivers/bus/*.o(.literal* .text*)
build/main.o(.literal* .text*)
*gccollect.o(.literal* .text*)

View File

@ -86,7 +86,7 @@ void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin);
} while (0)
#define mp_hal_pin_od_high(p) do { \
if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); } \
else { gpio_output_set(1 << (p), 0, 1 << (p), 0); } \
else { gpio_output_set(0, 0, 0, 1 << (p)); /* set as input to avoid glitches */ } \
} while (0)
#define mp_hal_pin_read(p) pin_get(p)
#define mp_hal_pin_write(p, v) pin_set((p), (v))

View File

@ -190,11 +190,8 @@ pwm_start(void)
// start
gpio_output_set(local_single[0].gpio_set, local_single[0].gpio_clear, pwm_gpio, 0);
// yeah, if all channels' duty is 0 or 255, don't need to start timer, otherwise start...
if (*local_channel != 1) {
pwm_timer_down = 0;
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time);
}
pwm_timer_down = 0;
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time);
}
if (pwm_toggle == 1) {
@ -210,12 +207,12 @@ pwm_start(void)
/******************************************************************************
* FunctionName : pwm_set_duty
* Description : set each channel's duty params
* Parameters : uint8 duty : 0 ~ PWM_DEPTH
* Parameters : int16_t duty : 0 ~ PWM_DEPTH
* uint8 channel : channel index
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
pwm_set_duty(uint16 duty, uint8 channel)
pwm_set_duty(int16_t duty, uint8 channel)
{
uint8 i;
for(i=0;i<pwm_channel_num;i++){
@ -319,11 +316,7 @@ pwm_tim1_intr_handler(void *dummy)
pwm_current_channel = 0;
if (*pwm_channel != 1) {
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time);
} else {
pwm_timer_down = 1;
}
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time);
} else {
gpio_output_set(pwm_single[pwm_current_channel].gpio_set,
pwm_single[pwm_current_channel].gpio_clear,

View File

@ -7,7 +7,7 @@
void pwm_init(void);
void pwm_start(void);
void pwm_set_duty(uint16_t duty, uint8_t channel);
void pwm_set_duty(int16_t duty, uint8_t channel);
uint16_t pwm_get_duty(uint8_t channel);
void pwm_set_freq(uint16_t freq, uint8_t channel);
uint16_t pwm_get_freq(uint8_t channel);

View File

@ -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;

View File

@ -1,32 +0,0 @@
# DHT11/DHT22 driver for MicroPython on ESP8266
# MIT license; Copyright (c) 2016 Damien P. George
import esp
class DHTBase:
def __init__(self, pin):
self.pin = pin
self.buf = bytearray(5)
def measure(self):
buf = self.buf
esp.dht_readinto(self.pin, buf)
if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]:
raise Exception("checksum error")
class DHT11(DHTBase):
def humidity(self):
return self.buf[0]
def temperature(self):
return self.buf[2]
class DHT22(DHTBase):
def humidity(self):
return (self.buf[0] << 8 | self.buf[1]) * 0.1
def temperature(self):
t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1
if self.buf[2] & 0x80:
t = -t
return t

View File

@ -0,0 +1 @@
../../../drivers/dht/dht.py

View File

@ -49,6 +49,7 @@
#define MICROPY_PY_ARRAY (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_COLLECTIONS (1)
#define MICROPY_PY_COLLECTIONS_DEQUE (1)
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
#define MICROPY_PY_MATH (1)
#define MICROPY_PY_CMATH (0)

View File

@ -276,7 +276,7 @@ void uart_task_handler(os_event_t *evt) {
int c, ret = 0;
while ((c = ringbuf_get(&input_buf)) >= 0) {
if (c == interrupt_char) {
if (c == mp_interrupt_char) {
mp_keyboard_interrupt();
}
ret = pyexec_event_repl_process_char(c);

View File

@ -41,13 +41,14 @@ LIBS =
SRC_C = \
main.c \
uart_core.c \
lib/utils/printf.c \
lib/utils/stdout_helpers.c \
lib/utils/pyexec.c \
lib/libc/string0.c \
lib/mp-readline/readline.c \
$(BUILD)/_frozen_mpy.c \
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
ifeq ($(CROSS), 1)
all: $(BUILD)/firmware.dfu

View File

@ -9,7 +9,7 @@ By default the port will be built for the host machine:
$ make
To run a small test script do:
To run the executable and get a basic working REPL do:
$ make run

View File

@ -37,6 +37,7 @@ DEVICE=0483:df11
STFLASH ?= st-flash
OPENOCD ?= openocd
OPENOCD_CONFIG ?= boards/openocd_stm32f4.cfg
STARTUP_FILE ?= boards/startup_stm32$(MCU_SERIES).o
CROSS_COMPILE = arm-none-eabi-
@ -53,16 +54,17 @@ INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc
CFLAGS_CORTEX_M = -mthumb
# Select hardware floating-point support
ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx))
ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx STM32H743xx))
CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard
else
CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
endif
# Options for particular MCU series
CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_F4
CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 -DMCU_SERIES_F7
CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 -DMCU_SERIES_L4
CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA)
CFLAGS += -D$(CMSIS_MCU)
@ -70,6 +72,7 @@ CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES))
CFLAGS += $(COPT)
CFLAGS += -Iboards/$(BOARD)
CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>'
CFLAGS += -DMICROPY_HW_VTOR=$(TEXT0_ADDR)
ifeq ($(MICROPY_FLOAT_IMPL),double)
CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_DOUBLE
@ -78,7 +81,7 @@ CFLAGS += -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT
CFLAGS += -fsingle-precision-constant -Wdouble-promotion
endif
LDFLAGS = -nostdlib -L $(LD_DIR) -T $(LD_FILE) -Map=$(@:.elf=.map) --cref
LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref
LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
# Remove uncalled code from the final image.
@ -185,7 +188,10 @@ EXTMOD_SRC_C = $(addprefix extmod/,\
)
DRIVERS_SRC_C = $(addprefix drivers/,\
bus/softspi.c \
bus/softqspi.c \
memory/spiflash.c \
dht/dht.c \
)
SRC_C = \
@ -212,6 +218,7 @@ SRC_C = \
dma.c \
i2c.c \
spi.c \
qspi.c \
uart.c \
can.c \
usb.c \
@ -231,6 +238,8 @@ SRC_C = \
rng.c \
rtc.c \
flash.c \
flashbdev.c \
spibdev.c \
storage.c \
sdcard.c \
fatfs_port.c \
@ -242,14 +251,14 @@ SRC_C = \
$(wildcard boards/$(BOARD)/*.c)
SRC_O = \
startup_stm32.o \
$(STARTUP_FILE) \
resethandler.o \
gchelper.o \
SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
hal.c \
hal_adc.c \
hal_adc_ex.c \
hal_can.c \
hal_cortex.c \
hal_dac.c \
hal_dac_ex.c \
@ -264,7 +273,6 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
hal_pwr_ex.c \
hal_rcc.c \
hal_rcc_ex.c \
hal_rng.c \
hal_rtc.c \
hal_rtc_ex.c \
hal_sd.c \
@ -276,6 +284,12 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
ll_usb.c \
)
ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx))
SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c)
else
SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c)
endif
SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\
core/src/usbd_core.c \
core/src/usbd_ctlreq.c \
@ -375,27 +389,50 @@ else
$(Q)$(DFU_UTIL) -a 0 -d $(DEVICE) -D $<
endif
FLASH_ADDR ?= 0x08000000
TEXT_ADDR ?= 0x08020000
# A board should specify TEXT0_ADDR if to use a different location than the
# default for the firmware memory location. A board can also optionally define
# TEXT1_ADDR to split the firmware into two sections; see below for details.
TEXT0_ADDR ?= 0x08000000
ifeq ($(TEXT1_ADDR),)
# No TEXT1_ADDR given so put all firmware at TEXT0_ADDR location
deploy-stlink: $(BUILD)/firmware.dfu
$(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK"
$(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(FLASH_ADDR)
$(ECHO) "Writing $(BUILD)/firmware1.bin to the board via ST-LINK"
$(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT_ADDR)
$(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK"
$(Q)$(STFLASH) write $(BUILD)/firmware.bin $(TEXT0_ADDR)
deploy-openocd: $(BUILD)/firmware.dfu
$(ECHO) "Writing $(BUILD)/firmware{0,1}.bin to the board via ST-LINK using OpenOCD"
$(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(FLASH_ADDR) $(BUILD)/firmware1.bin $(TEXT_ADDR)"
$(ECHO) "Writing $(BUILD)/firmware.bin to the board via ST-LINK using OpenOCD"
$(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware.bin $(TEXT0_ADDR)"
$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf
$(ECHO) "Create $@"
$(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin
$(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware.bin $@
else
# TEXT0_ADDR and TEXT1_ADDR are specified so split firmware between these locations
deploy-stlink: $(BUILD)/firmware.dfu
$(ECHO) "Writing $(BUILD)/firmware0.bin to the board via ST-LINK"
$(Q)$(STFLASH) write $(BUILD)/firmware0.bin $(TEXT0_ADDR)
$(ECHO) "Writing $(BUILD)/firmware1.bin to the board via ST-LINK"
$(Q)$(STFLASH) --reset write $(BUILD)/firmware1.bin $(TEXT1_ADDR)
deploy-openocd: $(BUILD)/firmware.dfu
$(ECHO) "Writing $(BUILD)/firmware{0,1}.bin to the board via ST-LINK using OpenOCD"
$(Q)$(OPENOCD) -f $(OPENOCD_CONFIG) -c "stm_flash $(BUILD)/firmware0.bin $(TEXT0_ADDR) $(BUILD)/firmware1.bin $(TEXT1_ADDR)"
$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf
$(ECHO) "GEN $@"
$(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $(BUILD)/firmware0.bin
$(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $(BUILD)/firmware1.bin
$(Q)$(PYTHON) $(DFU) -b $(FLASH_ADDR):$(BUILD)/firmware0.bin -b $(TEXT_ADDR):$(BUILD)/firmware1.bin $@
$(Q)$(PYTHON) $(DFU) -b $(TEXT0_ADDR):$(BUILD)/firmware0.bin -b $(TEXT1_ADDR):$(BUILD)/firmware1.bin $@
endif
$(BUILD)/firmware.hex: $(BUILD)/firmware.elf
$(ECHO) "Create $@"
$(ECHO) "GEN $@"
$(Q)$(OBJCOPY) -O ihex $< $@
$(BUILD)/firmware.elf: $(OBJ)
@ -444,7 +481,7 @@ main.c: $(GEN_CDCINF_HEADER)
# Use a pattern rule here so that make will only call make-pins.py once to make
# both pins_$(BOARD).c and pins.h
$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
$(ECHO) "Create $@"
$(ECHO) "GEN $@"
$(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC)
$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
@ -459,22 +496,22 @@ CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h
modmachine.c: $(GEN_PLLFREQTABLE_HDR)
$(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD)
$(ECHO) "Create $@"
$(ECHO) "GEN $@"
$(Q)$(PYTHON) $(PLLVALUES) -c file:boards/$(BOARD)/stm32$(MCU_SERIES)xx_hal_conf.h > $@
$(BUILD)/modstm.o: $(GEN_STMCONST_HDR)
# Use a pattern rule here so that make will only call make-stmconst.py once to
# make both modstm_const.h and modstm_qstr.h
$(HEADER_BUILD)/%_const.h $(BUILD)/%_qstr.h: $(CMSIS_MCU_HDR) make-stmconst.py | $(HEADER_BUILD)
$(ECHO) "Create stmconst $@"
$(ECHO) "GEN stmconst $@"
$(Q)$(PYTHON) make-stmconst.py --qstr $(GEN_STMCONST_QSTR) --mpz $(GEN_STMCONST_MPZ) $(CMSIS_MCU_HDR) > $(GEN_STMCONST_HDR)
$(GEN_CDCINF_HEADER): $(GEN_CDCINF_FILE) $(FILE2H) | $(HEADER_BUILD)
$(ECHO) "Create $@"
$(ECHO) "GEN $@"
$(Q)$(PYTHON) $(FILE2H) $< > $@
$(GEN_CDCINF_FILE): $(CDCINF_TEMPLATE) $(INSERT_USB_IDS) $(USB_IDS_FILE) | $(HEADER_BUILD)
$(ECHO) "Create $@"
$(ECHO) "GEN $@"
$(Q)$(PYTHON) $(INSERT_USB_IDS) $(USB_IDS_FILE) $< > $@
include $(TOP)/py/mkrules.mk

View File

@ -30,7 +30,6 @@
#include "py/mphal.h"
#include "py/runtime.h"
#include "pin.h"
#include "genhdr/pins.h"
#include "i2c.h"
#include "accel.h"
@ -57,8 +56,8 @@
void accel_init(void) {
// PB5 is connected to AVDD; pull high to enable MMA accel device
mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD
mp_hal_pin_output(&MICROPY_HW_MMA_AVDD_PIN);
mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD
mp_hal_pin_output(MICROPY_HW_MMA_AVDD_PIN);
}
STATIC void accel_start(void) {
@ -74,9 +73,9 @@ STATIC void accel_start(void) {
i2c_init(&I2CHandle1);
// turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again
mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off
mp_hal_pin_low(MICROPY_HW_MMA_AVDD_PIN); // turn off
mp_hal_delay_ms(30);
mp_hal_pin_high(&MICROPY_HW_MMA_AVDD_PIN); // turn on
mp_hal_pin_high(MICROPY_HW_MMA_AVDD_PIN); // turn on
mp_hal_delay_ms(30);
HAL_StatusTypeDef status;

View File

@ -23,11 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_STMHAL_ACCEL_H
#define MICROPY_INCLUDED_STMHAL_ACCEL_H
#ifndef MICROPY_INCLUDED_STM32_ACCEL_H
#define MICROPY_INCLUDED_STM32_ACCEL_H
extern const mp_obj_type_t pyb_accel_type;
void accel_init(void);
#endif // MICROPY_INCLUDED_STMHAL_ACCEL_H
#endif // MICROPY_INCLUDED_STM32_ACCEL_H

View File

@ -32,9 +32,10 @@
#include "py/mphal.h"
#include "adc.h"
#include "pin.h"
#include "genhdr/pins.h"
#include "timer.h"
#if MICROPY_HW_ENABLE_ADC
/// \moduleref pyb
/// \class ADC - analog to digital conversion: read analog values on a pin
///
@ -51,10 +52,10 @@
/* ADC defintions */
#define ADCx (ADC1)
#define ADCx_CLK_ENABLE __ADC1_CLK_ENABLE
#define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE
#define ADC_NUM_CHANNELS (19)
#if defined(MCU_SERIES_F4)
#if defined(STM32F4)
#define ADC_FIRST_GPIO_CHANNEL (0)
#define ADC_LAST_GPIO_CHANNEL (15)
@ -62,15 +63,21 @@
#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2))
#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4))
#elif defined(MCU_SERIES_F7)
#elif defined(STM32F7)
#define ADC_FIRST_GPIO_CHANNEL (0)
#define ADC_LAST_GPIO_CHANNEL (15)
#if defined(STM32F722xx) || defined(STM32F723xx) || \
defined(STM32F732xx) || defined(STM32F733xx)
#define ADC_CAL_ADDRESS (0x1ff07a2a)
#else
#define ADC_CAL_ADDRESS (0x1ff0f44a)
#endif
#define ADC_CAL1 ((uint16_t*)(ADC_CAL_ADDRESS + 2))
#define ADC_CAL2 ((uint16_t*)(ADC_CAL_ADDRESS + 4))
#elif defined(MCU_SERIES_L4)
#elif defined(STM32L4)
#define ADC_FIRST_GPIO_CHANNEL (1)
#define ADC_LAST_GPIO_CHANNEL (16)
@ -91,6 +98,8 @@
#define VBAT_DIV (2)
#elif defined(STM32F427xx) || defined(STM32F429xx) || \
defined(STM32F437xx) || defined(STM32F439xx) || \
defined(STM32F722xx) || defined(STM32F723xx) || \
defined(STM32F732xx) || defined(STM32F733xx) || \
defined(STM32F746xx) || defined(STM32F767xx) || \
defined(STM32F769xx) || defined(STM32F446xx)
#define VBAT_DIV (4)
@ -117,7 +126,7 @@ typedef struct _pyb_obj_adc_t {
// convert user-facing channel number into internal channel number
static inline uint32_t adc_get_internal_channel(uint32_t channel) {
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
// on F4 and F7 MCUs we want channel 16 to always be the TEMPSENSOR
// (on some MCUs ADC_CHANNEL_TEMPSENSOR=16, on others it doesn't)
if (channel == 16) {
@ -128,9 +137,9 @@ static inline uint32_t adc_get_internal_channel(uint32_t channel) {
}
STATIC bool is_adcx_channel(int channel) {
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
return IS_ADC_CHANNEL(channel);
#elif defined(MCU_SERIES_L4)
#elif defined(STM32L4)
ADC_HandleTypeDef handle;
handle.Instance = ADCx;
return IS_ADC_CHANNEL(&handle, channel);
@ -141,9 +150,9 @@ STATIC bool is_adcx_channel(int channel) {
STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
uint32_t tickstart = HAL_GetTick();
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
#elif defined(MCU_SERIES_L4)
#elif defined(STM32L4)
while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
#else
#error Unsupported processor
@ -155,9 +164,9 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
}
STATIC void adcx_clock_enable(void) {
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
ADCx_CLK_ENABLE();
#elif defined(MCU_SERIES_L4)
#elif defined(STM32L4)
__HAL_RCC_ADC_CLK_ENABLE();
#else
#error Unsupported processor
@ -176,9 +185,9 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
mp_hal_gpio_clock_enable(pin->gpio);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = pin->pin_mask;
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
#elif defined(MCU_SERIES_L4)
#elif defined(STM32L4)
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
#else
#error Unsupported processor
@ -199,12 +208,12 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
adcHandle->Init.NbrOfConversion = 1;
adcHandle->Init.DMAContinuousRequests = DISABLE;
adcHandle->Init.Resolution = ADC_RESOLUTION_12B;
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
adcHandle->Init.ScanConvMode = DISABLE;
adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
adcHandle->Init.EOCSelection = DISABLE;
#elif defined(MCU_SERIES_L4)
#elif defined(STM32L4)
adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE;
adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV;
@ -219,7 +228,7 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
HAL_ADC_Init(adcHandle);
#if defined(MCU_SERIES_L4)
#if defined(STM32L4)
ADC_MultiModeTypeDef multimode;
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(adcHandle, &multimode) != HAL_OK)
@ -234,9 +243,9 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
sConfig.Channel = channel;
sConfig.Rank = 1;
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
#elif defined(MCU_SERIES_L4)
#elif defined(STM32L4)
sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
@ -253,7 +262,7 @@ STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) {
HAL_ADC_Start(adcHandle);
if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK
&& (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_EOC_REG) == HAL_ADC_STATE_EOC_REG) {
&& (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC) {
rawValue = HAL_ADC_GetValue(adcHandle);
}
HAL_ADC_Stop(adcHandle);
@ -401,9 +410,9 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
HAL_ADC_Start(&self->handle);
} else {
// for subsequent samples we can just set the "start sample" bit
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
#elif defined(MCU_SERIES_L4)
#elif defined(STM32L4)
SET_BIT(ADCx->CR, ADC_CR_ADSTART);
#else
#error Unsupported processor
@ -503,11 +512,11 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m
adcHandle->Init.NbrOfConversion = 1;
adcHandle->Init.DMAContinuousRequests = DISABLE;
adcHandle->Init.EOCSelection = DISABLE;
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
adcHandle->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
adcHandle->Init.ScanConvMode = DISABLE;
adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
#elif defined(MCU_SERIES_L4)
#elif defined(STM32L4)
adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE;
adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1;
@ -527,7 +536,7 @@ uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t chan
}
int adc_get_resolution(ADC_HandleTypeDef *adcHandle) {
uint32_t res_reg = __HAL_ADC_GET_RESOLUTION(adcHandle);
uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle);
switch (res_reg) {
case ADC_RESOLUTION_6B: return 6;
@ -568,7 +577,7 @@ float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) {
// be 12-bits.
raw_value <<= (12 - adc_get_resolution(adcHandle));
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
#if defined(STM32F4) || defined(STM32F7)
// ST docs say that (at least on STM32F42x and STM32F43x), VBATE must
// be disabled when TSVREFE is enabled for TEMPSENSOR and VREFINT
// conversions to work. VBATE is enabled by the above call to read
@ -675,3 +684,5 @@ const mp_obj_type_t pyb_adc_all_type = {
.make_new = adc_all_make_new,
.locals_dict = (mp_obj_dict_t*)&adc_all_locals_dict,
};
#endif // MICROPY_HW_ENABLE_ADC

View File

@ -23,10 +23,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_STMHAL_ADC_H
#define MICROPY_INCLUDED_STMHAL_ADC_H
#ifndef MICROPY_INCLUDED_STM32_ADC_H
#define MICROPY_INCLUDED_STM32_ADC_H
extern const mp_obj_type_t pyb_adc_type;
extern const mp_obj_type_t pyb_adc_all_type;
#endif // MICROPY_INCLUDED_STMHAL_ADC_H
#endif // MICROPY_INCLUDED_STM32_ADC_H

View File

@ -2,17 +2,9 @@
#define MICROPY_HW_MCU_NAME "STM32L475"
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (0)
#define MICROPY_HW_HAS_SDCARD (0)
#define MICROPY_HW_HAS_MMA7660 (0)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (0)
#define MICROPY_HW_ENABLE_CAN (0)
#define MICROPY_HW_ENABLE_USB (1)
// MSI is used and is 4MHz
#define MICROPY_HW_CLK_PLLM (1)
@ -74,3 +66,6 @@
#define MICROPY_HW_LED2 (pin_B14) // green
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config
#define MICROPY_HW_USB_FS (1)

View File

@ -3,6 +3,7 @@ CMSIS_MCU = STM32L475xx
# The stm32l475 does not have a LDC controller which is
# the only diffrence to the stm32l476 - so reuse some files.
AF_FILE = boards/stm32l476_af.csv
LD_FILE = boards/stm32l476xg.ld
TEXT_ADDR = 0x08004000
LD_FILES = boards/stm32l476xg.ld boards/common_ifs.ld
TEXT0_ADDR = 0x08000000
TEXT1_ADDR = 0x08004000
OPENOCD_CONFIG = boards/openocd_stm32l4.cfg

View File

@ -45,7 +45,6 @@
extern "C" {
#endif
#define USE_USB_FS
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/

View File

@ -1,18 +1,12 @@
#define MICROPY_HW_BOARD_NAME "Cerb40"
#define MICROPY_HW_MCU_NAME "STM32F405RG"
#define MICROPY_HW_HAS_SWITCH (0)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (0)
#define MICROPY_HW_HAS_MMA7660 (0)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (1)
#define MICROPY_HW_ENABLE_CAN (1)
#define MICROPY_HW_ENABLE_USB (1)
// HSE is 12MHz
#define MICROPY_HW_CLK_PLLM (12)
@ -61,5 +55,6 @@
// The Cerb40 has No SDCard
// USB config
#define MICROPY_HW_USB_FS (1)
//#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
//#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)

View File

@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F405xx
AF_FILE = boards/stm32f405_af.csv
LD_FILE = boards/stm32f405.ld
LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
TEXT0_ADDR = 0x08000000
TEXT1_ADDR = 0x08020000

View File

@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
#define USE_USB_FS
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver

View File

@ -9,16 +9,9 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (0)
#define MICROPY_HW_HAS_MMA7660 (0)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (0)
#define MICROPY_HW_ENABLE_RTC (1)
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (0)
#define MICROPY_HW_ENABLE_CAN (0)
// Pico has an 8 MHz HSE and the F401 does 84 MHz max
#define MICROPY_HW_CLK_PLLM (5)
@ -70,3 +63,6 @@
#define MICROPY_HW_LED4 (pin_B12) // green
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config
#define MICROPY_HW_USB_FS (1)

View File

@ -1,7 +1,9 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F401xE
AF_FILE = boards/stm32f401_af.csv
LD_FILE = boards/stm32f401xd.ld
LD_FILES = boards/stm32f401xd.ld boards/common_ifs.ld
TEXT0_ADDR = 0x08000000
TEXT1_ADDR = 0x08020000
# Don't include default frozen modules because MCU is tight on flash space
FROZEN_MPY_DIR ?=

View File

@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
#define USE_USB_FS
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver

View File

@ -4,15 +4,9 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (1)
#define MICROPY_HW_HAS_MMA7660 (0)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (0)
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (1)
#define MICROPY_HW_ENABLE_CAN (0)
#define MICROPY_HW_ENABLE_USB (1)
// HSE is 8MHz
#define MICROPY_HW_CLK_PLLM (8)
@ -76,4 +70,5 @@
#define MICROPY_HW_SDCARD_DETECT_PRESENT (1)
// USB config
#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)

View File

@ -1,4 +1,6 @@
MCU_SERIES = f4
CMSIS_MCU = STM32F405xx
AF_FILE = boards/stm32f405_af.csv
LD_FILE = boards/stm32f405.ld
LD_FILES = boards/stm32f405.ld boards/common_ifs.ld
TEXT0_ADDR = 0x08000000
TEXT1_ADDR = 0x08020000

View File

@ -46,8 +46,6 @@
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
#define USE_USB_FS
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver

View File

@ -104,10 +104,10 @@ static void LBF_DFU_If_Needed(void)
// Initialize and assert pin BTLE_RST
// (hw reset to BLE module, so it won't drive UART3)
__GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pin = BT_RST_PIN;
HAL_GPIO_Init(BT_RST_PORT, &GPIO_InitStruct);
@ -124,7 +124,7 @@ static void LBF_DFU_If_Needed(void)
// Initialize Extension Port Position 10 = PB8 (bears I2C1_SCL)
// Use weak pull-up to detect if pin is externally pulled low
__GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Pin = CONN_POS10_PIN;

View File

@ -3,16 +3,9 @@
#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_HAS_SDCARD (0)
#define MICROPY_HW_HAS_MMA7660 (0)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (1)
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_SERVO (0)
#define MICROPY_HW_ENABLE_DAC (0)
#define MICROPY_HW_ENABLE_CAN (0)
#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_BOARD_EARLY_INIT LIMIFROG_board_early_init
void LIMIFROG_board_early_init(void);
@ -58,4 +51,5 @@ void LIMIFROG_board_early_init(void);
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB config
#define MICROPY_HW_USB_FS (1)
// #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10

View File

@ -1,5 +1,6 @@
MCU_SERIES = l4
CMSIS_MCU = STM32L476xx
AF_FILE = boards/stm32l476_af.csv
LD_FILE = boards/stm32l476xe.ld
TEXT_ADDR = 0x08004000
LD_FILES = boards/stm32l476xe.ld boards/common_ifs.ld
TEXT0_ADDR = 0x08000000
TEXT1_ADDR = 0x08004000

View File

@ -45,7 +45,6 @@
extern "C" {
#endif
#define USE_USB_FS
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/

View File

@ -2,11 +2,11 @@
void NETDUINO_PLUS_2_board_early_init(void) {
__GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
// Turn off the backlight. LCD_BL_CTRL = PK3
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_PULLUP;

View File

@ -8,15 +8,9 @@
// SPI, so the driver needs to be converted to support that before
// we can turn this on.
#define MICROPY_HW_HAS_SDCARD (0)
#define MICROPY_HW_HAS_MMA7660 (0)
#define MICROPY_HW_HAS_LIS3DSH (0)
#define MICROPY_HW_HAS_LCD (0)
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_ENABLE_RTC (0)
#define MICROPY_HW_ENABLE_TIMER (1)
#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_ENABLE_SERVO (1)
#define MICROPY_HW_ENABLE_DAC (0)
#define MICROPY_HW_ENABLE_CAN (0)
void NETDUINO_PLUS_2_board_early_init(void);
#define MICROPY_BOARD_EARLY_INIT NETDUINO_PLUS_2_board_early_init
@ -69,5 +63,6 @@ void NETDUINO_PLUS_2_board_early_init(void);
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
// USB VBUS detect pin
// USB config
#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)

Some files were not shown because too many files have changed in this diff Show More