Merge branch 'master' into pr3
This commit is contained in:
commit
b8a5167517
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -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
|
||||
|
||||
39
.travis.yml
39
.travis.yml
@ -6,6 +6,8 @@ compiler:
|
||||
cache:
|
||||
directories:
|
||||
- "${HOME}/persist"
|
||||
env:
|
||||
- MAKEOPTS="-j4"
|
||||
|
||||
before_script:
|
||||
# Extra CPython versions
|
||||
@ -26,44 +28,47 @@ before_script:
|
||||
- python3 --version
|
||||
|
||||
script:
|
||||
- make -C mpy-cross
|
||||
- make -C ports/minimal CROSS=1 build/firmware.bin
|
||||
- make ${MAKEOPTS} -C mpy-cross
|
||||
- make ${MAKEOPTS} -C ports/minimal CROSS=1 build/firmware.bin
|
||||
- ls -l ports/minimal/build/firmware.bin
|
||||
- tools/check_code_size.sh
|
||||
- mkdir -p ${HOME}/persist
|
||||
# Save new firmware for reference, but only if building a main branch, not a pull request
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cp ports/minimal/build/firmware.bin ${HOME}/persist/; fi'
|
||||
- make -C ports/unix deplibs
|
||||
- make -C ports/unix
|
||||
- make -C ports/unix nanbox
|
||||
- make -C ports/bare-arm
|
||||
- make -C ports/qemu-arm -f Makefile.test test
|
||||
- make -C ports/stm32
|
||||
- make -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1
|
||||
- make -C ports/stm32 BOARD=STM32F769DISC
|
||||
- make -C ports/stm32 BOARD=STM32L476DISC
|
||||
- make -C ports/teensy
|
||||
- make -C ports/cc3200 BTARGET=application BTYPE=release
|
||||
- make -C ports/cc3200 BTARGET=bootloader BTYPE=release
|
||||
- make -C ports/windows CROSS_COMPILE=i686-w64-mingw32-
|
||||
- make ${MAKEOPTS} -C ports/unix deplibs
|
||||
- make ${MAKEOPTS} -C ports/unix
|
||||
- make ${MAKEOPTS} -C ports/unix nanbox
|
||||
- make ${MAKEOPTS} -C ports/bare-arm
|
||||
- make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test test
|
||||
- make ${MAKEOPTS} -C ports/stm32
|
||||
- make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1
|
||||
- make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC
|
||||
- make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC
|
||||
- make ${MAKEOPTS} -C ports/teensy
|
||||
- make ${MAKEOPTS} -C ports/cc3200 BTARGET=application BTYPE=release
|
||||
- make ${MAKEOPTS} -C ports/cc3200 BTARGET=bootloader BTYPE=release
|
||||
- make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32-
|
||||
|
||||
# run tests without coverage info
|
||||
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests)
|
||||
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests --emit native)
|
||||
|
||||
# run tests with coverage info
|
||||
- make -C ports/unix coverage
|
||||
- make ${MAKEOPTS} -C ports/unix coverage
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float)
|
||||
|
||||
# test when input script comes from stdin
|
||||
- cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc'
|
||||
|
||||
# run coveralls coverage analysis (try to, even if some builds/tests failed)
|
||||
- (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod)
|
||||
|
||||
# run tests on stackless build
|
||||
- rm -rf ports/unix/build-coverage
|
||||
- make -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1"
|
||||
- make ${MAKEOPTS} -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1"
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests)
|
||||
|
||||
after_failure:
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()`.
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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')
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
57
drivers/bus/qspi.h
Normal 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
203
drivers/bus/softqspi.c
Normal 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
105
drivers/bus/softspi.c
Normal 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
55
drivers/bus/spi.h
Normal 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
|
||||
@ -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
35
drivers/dht/dht.py
Normal 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
|
||||
@ -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):
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) },
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 :
|
||||
|
||||
@ -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
162
ports/esp32/machine_rtc.c
Normal 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
44
ports/esp32/machine_rtc.h
Normal 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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
138
ports/esp32/modesp32.c
Normal 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
29
ports/esp32/modesp32.h
Normal 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
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -1 +1 @@
|
||||
../../esp8266/modules/dht.py
|
||||
../../../drivers/dht/dht.py
|
||||
@ -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 }, \
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
```
|
||||
|
||||
@ -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*)
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
1
ports/esp8266/modules/dht.py
Symbolic link
1
ports/esp8266/modules/dht.py
Symbolic link
@ -0,0 +1 @@
|
||||
../../../drivers/dht/dht.py
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -45,7 +45,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define USE_USB_FS
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 ?=
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -45,7 +45,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define USE_USB_FS
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
Loading…
Reference in New Issue
Block a user