Update Micropython
This commit is contained in:
commit
377068c5f2
@ -1,3 +1,6 @@
|
|||||||
|
# tools/gen-cpydiff.py: Fix formatting of doc strings for new Black.
|
||||||
|
0f78c36c5aa458a954eed39a46942209107a553e
|
||||||
|
|
||||||
# tests/run-tests.py: Reformat with Black.
|
# tests/run-tests.py: Reformat with Black.
|
||||||
2a38d7103672580882fb621a5b76e8d26805d593
|
2a38d7103672580882fb621a5b76e8d26805d593
|
||||||
|
|
||||||
|
|||||||
23
.github/workflows/ports_mimxrt.yml
vendored
Normal file
23
.github/workflows/ports_mimxrt.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: mimxrt port
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/*.yml'
|
||||||
|
- 'tools/**'
|
||||||
|
- 'py/**'
|
||||||
|
- 'extmod/**'
|
||||||
|
- 'lib/**'
|
||||||
|
- 'drivers/**'
|
||||||
|
- 'ports/mimxrt/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install packages
|
||||||
|
run: source tools/ci.sh && ci_mimxrt_setup
|
||||||
|
- name: Build
|
||||||
|
run: source tools/ci.sh && ci_mimxrt_build
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@ -9,6 +9,9 @@
|
|||||||
*.dis
|
*.dis
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
|
lextab.py
|
||||||
|
yacctab.py
|
||||||
|
|
||||||
# Packages
|
# Packages
|
||||||
############
|
############
|
||||||
|
|
||||||
@ -55,5 +58,6 @@ ports/javascript/node_modules
|
|||||||
######################
|
######################
|
||||||
genrst/
|
genrst/
|
||||||
|
|
||||||
lextab.py
|
# MacOS desktop metadata files
|
||||||
yacctab.py
|
######################
|
||||||
|
.DS_Store
|
||||||
|
|||||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -7,7 +7,7 @@
|
|||||||
url = https://github.com/atgreen/libffi
|
url = https://github.com/atgreen/libffi
|
||||||
[submodule "lib/lwip"]
|
[submodule "lib/lwip"]
|
||||||
path = lib/lwip
|
path = lib/lwip
|
||||||
url = https://git.savannah.gnu.org/r/lwip.git
|
url = https://github.com/lwip-tcpip/lwip.git
|
||||||
[submodule "lib/berkeley-db-1.xx"]
|
[submodule "lib/berkeley-db-1.xx"]
|
||||||
path = lib/berkeley-db-1.xx
|
path = lib/berkeley-db-1.xx
|
||||||
url = https://github.com/pfalcon/berkeley-db-1.xx
|
url = https://github.com/pfalcon/berkeley-db-1.xx
|
||||||
|
|||||||
@ -91,7 +91,7 @@ This simple module named ``cexample`` provides a single function
|
|||||||
``cexample.add_ints(a, b)`` which adds the two integer args together and returns
|
``cexample.add_ints(a, b)`` which adds the two integer args together and returns
|
||||||
the result. It can be found in the MicroPython source tree
|
the result. It can be found in the MicroPython source tree
|
||||||
`in the examples directory <https://github.com/micropython/micropython/tree/master/examples/usercmodule/cexample>`_
|
`in the examples directory <https://github.com/micropython/micropython/tree/master/examples/usercmodule/cexample>`_
|
||||||
and has a source file and a Makefile fragment with content as descibed above::
|
and has a source file and a Makefile fragment with content as described above::
|
||||||
|
|
||||||
micropython/
|
micropython/
|
||||||
└──examples/
|
└──examples/
|
||||||
|
|||||||
@ -58,7 +58,7 @@ The :mod:`esp32` module::
|
|||||||
import esp32
|
import esp32
|
||||||
|
|
||||||
esp32.hall_sensor() # read the internal hall sensor
|
esp32.hall_sensor() # read the internal hall sensor
|
||||||
esp32.raw_temperature() # read the internal temperature of the MCU, in Farenheit
|
esp32.raw_temperature() # read the internal temperature of the MCU, in Fahrenheit
|
||||||
esp32.ULP() # access to the Ultra-Low-Power Co-processor
|
esp32.ULP() # access to the Ultra-Low-Power Co-processor
|
||||||
|
|
||||||
Note that the temperature sensor in the ESP32 will typically read higher than
|
Note that the temperature sensor in the ESP32 will typically read higher than
|
||||||
@ -171,6 +171,37 @@ Notes:
|
|||||||
* The pull value of some pins can be set to ``Pin.PULL_HOLD`` to reduce power
|
* The pull value of some pins can be set to ``Pin.PULL_HOLD`` to reduce power
|
||||||
consumption during deepsleep.
|
consumption during deepsleep.
|
||||||
|
|
||||||
|
There's a higher-level abstraction :ref:`machine.Signal <machine.Signal>`
|
||||||
|
which can be used to invert a pin. Useful for illuminating active-low LEDs
|
||||||
|
using ``on()`` or ``value(1)``.
|
||||||
|
|
||||||
|
UART (serial bus)
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
See :ref:`machine.UART <machine.UART>`. ::
|
||||||
|
|
||||||
|
from machine import UART
|
||||||
|
|
||||||
|
uart1 = UART(1, baudrate=9600, tx=33, rx=32)
|
||||||
|
uart1.write('hello') # write 5 bytes
|
||||||
|
uart1.read(5) # read up to 5 bytes
|
||||||
|
|
||||||
|
The ESP32 has three hardware UARTs: UART0, UART1 and UART2.
|
||||||
|
They each have default GPIO assigned to them, however depending on your
|
||||||
|
ESP32 variant and board, these pins may conflict with embedded flash,
|
||||||
|
onboard PSRAM or peripherals.
|
||||||
|
|
||||||
|
Any GPIO can be used for hardware UARTs using the GPIO matrix, so to avoid
|
||||||
|
conflicts simply provide ``tx`` and ``rx`` pins when constructing. The default
|
||||||
|
pins listed below.
|
||||||
|
|
||||||
|
===== ===== ===== =====
|
||||||
|
\ UART0 UART1 UART2
|
||||||
|
===== ===== ===== =====
|
||||||
|
tx 1 10 17
|
||||||
|
rx 3 9 16
|
||||||
|
===== ===== ===== =====
|
||||||
|
|
||||||
PWM (pulse width modulation)
|
PWM (pulse width modulation)
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
@ -357,6 +388,17 @@ See :ref:`machine.RTC <machine.RTC>` ::
|
|||||||
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time
|
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time
|
||||||
rtc.datetime() # get date and time
|
rtc.datetime() # get date and time
|
||||||
|
|
||||||
|
WDT (Watchdog timer)
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
See :ref:`machine.WDT <machine.WDT>`. ::
|
||||||
|
|
||||||
|
from machine import WDT
|
||||||
|
|
||||||
|
# enable the WDT with a timeout of 5s (1s is the minimum)
|
||||||
|
wdt = WDT(timeout=5000)
|
||||||
|
wdt.feed()
|
||||||
|
|
||||||
Deep-sleep mode
|
Deep-sleep mode
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@ -386,6 +428,21 @@ Notes:
|
|||||||
|
|
||||||
p1 = Pin(4, Pin.OUT, None)
|
p1 = Pin(4, Pin.OUT, None)
|
||||||
|
|
||||||
|
SD card
|
||||||
|
-------
|
||||||
|
|
||||||
|
See :ref:`machine.SDCard <machine.SDCard>`. ::
|
||||||
|
|
||||||
|
import machine, uos
|
||||||
|
|
||||||
|
# Slot 2 uses pins sck=18, cs=5, miso=19, mosi=23
|
||||||
|
sd = machine.SDCard(slot=2)
|
||||||
|
uos.mount(sd, "/sd") # mount
|
||||||
|
|
||||||
|
uos.listdir('/sd') # list directory contents
|
||||||
|
|
||||||
|
uos.umount('/sd') # eject
|
||||||
|
|
||||||
RMT
|
RMT
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -430,10 +487,10 @@ Be sure to put a 4.7k pull-up resistor on the data line. Note that
|
|||||||
the ``convert_temp()`` method must be called each time you want to
|
the ``convert_temp()`` method must be called each time you want to
|
||||||
sample the temperature.
|
sample the temperature.
|
||||||
|
|
||||||
NeoPixel driver
|
NeoPixel and APA106 driver
|
||||||
---------------
|
--------------------------
|
||||||
|
|
||||||
Use the ``neopixel`` module::
|
Use the ``neopixel`` and ``apa106`` modules::
|
||||||
|
|
||||||
from machine import Pin
|
from machine import Pin
|
||||||
from neopixel import NeoPixel
|
from neopixel import NeoPixel
|
||||||
@ -444,6 +501,13 @@ Use the ``neopixel`` module::
|
|||||||
np.write() # write data to all pixels
|
np.write() # write data to all pixels
|
||||||
r, g, b = np[0] # get first pixel colour
|
r, g, b = np[0] # get first pixel colour
|
||||||
|
|
||||||
|
|
||||||
|
The APA106 driver extends NeoPixel, but internally uses a different colour order::
|
||||||
|
|
||||||
|
from apa106 import APA106
|
||||||
|
ap = APA106(pin, 8)
|
||||||
|
r, g, b = ap[0]
|
||||||
|
|
||||||
For low-level driving of a NeoPixel::
|
For low-level driving of a NeoPixel::
|
||||||
|
|
||||||
import esp
|
import esp
|
||||||
@ -455,6 +519,7 @@ For low-level driving of a NeoPixel::
|
|||||||
400kHz) devices by passing ``timing=0`` when constructing the
|
400kHz) devices by passing ``timing=0`` when constructing the
|
||||||
``NeoPixel`` object.
|
``NeoPixel`` object.
|
||||||
|
|
||||||
|
APA102 (DotStar) uses a different driver as it has an additional clock pin.
|
||||||
|
|
||||||
Capacitive touch
|
Capacitive touch
|
||||||
----------------
|
----------------
|
||||||
|
|||||||
@ -125,6 +125,16 @@ will overflow every 7:45h. If a long-term working RTC time is required then
|
|||||||
``time()`` or ``localtime()`` must be called at least once within 7 hours.
|
``time()`` or ``localtime()`` must be called at least once within 7 hours.
|
||||||
MicroPython will then handle the overflow.
|
MicroPython will then handle the overflow.
|
||||||
|
|
||||||
|
Simultaneous operation of STA_IF and AP_IF
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Simultaneous operation of STA_IF and AP_IF interfaces is supported.
|
||||||
|
|
||||||
|
However, due to restrictions of the hardware, there may be performance
|
||||||
|
issues in the AP_IF, if the STA_IF is not connected and searching.
|
||||||
|
An application should manage these interfaces and for example
|
||||||
|
deactivate the STA_IF in environments where only the AP_IF is used.
|
||||||
|
|
||||||
Sockets and WiFi buffers overflow
|
Sockets and WiFi buffers overflow
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -153,25 +163,26 @@ SSL/TLS limitations
|
|||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
ESP8266 uses `axTLS <http://axtls.sourceforge.net/>`_ library, which is one
|
ESP8266 uses `axTLS <http://axtls.sourceforge.net/>`_ library, which is one
|
||||||
of the smallest TLS libraries with the compatible licensing. However, it
|
of the smallest TLS libraries with compatible licensing. However, it
|
||||||
also has some known issues/limitations:
|
also has some known issues/limitations:
|
||||||
|
|
||||||
1. No support for Diffie-Hellman (DH) key exchange and Elliptic-curve
|
1. No support for Diffie-Hellman (DH) key exchange and Elliptic-curve
|
||||||
cryptography (ECC). This means it can't work with sites which force
|
cryptography (ECC). This means it can't work with sites which require
|
||||||
the use of these features (it works ok with classic RSA certificates).
|
the use of these features (it works ok with the typical sites that use
|
||||||
|
RSA certificates).
|
||||||
2. Half-duplex communication nature. axTLS uses a single buffer for both
|
2. Half-duplex communication nature. axTLS uses a single buffer for both
|
||||||
sending and receiving, which leads to considerable memory saving and
|
sending and receiving, which leads to considerable memory saving and
|
||||||
works well with protocols like HTTP. But there may be problems with
|
works well with protocols like HTTP. But there may be problems with
|
||||||
protocols which don't follow classic request-response model.
|
protocols which don't follow classic request-response model.
|
||||||
|
|
||||||
Besides axTLS own limitations, the configuration used for MicroPython is
|
Besides axTLS's own limitations, the configuration used for MicroPython is
|
||||||
highly optimized for code size, which leads to additional limitations
|
highly optimized for code size, which leads to additional limitations
|
||||||
(these may be lifted in the future):
|
(these may be lifted in the future):
|
||||||
|
|
||||||
3. Optimized RSA algorithms are not enabled, which may lead to slow
|
3. Optimized RSA algorithms are not enabled, which may lead to slow
|
||||||
SSL handshakes.
|
SSL handshakes.
|
||||||
4. Stored sessions are not supported (may allow faster repeated connections
|
4. Session Reuse is not enabled, which means every connection must undergo
|
||||||
to the same site in some circumstances).
|
the full, expensive SSL handshake.
|
||||||
|
|
||||||
Besides axTLS specific limitations described above, there's another generic
|
Besides axTLS specific limitations described above, there's another generic
|
||||||
limitation with usage of TLS on the low-memory devices:
|
limitation with usage of TLS on the low-memory devices:
|
||||||
@ -185,13 +196,16 @@ limitation with usage of TLS on the low-memory devices:
|
|||||||
accessing various REST APIs, which usually require much smaller messages.
|
accessing various REST APIs, which usually require much smaller messages.
|
||||||
The buffers size is on the order of 5KB, and is adjusted from time to
|
The buffers size is on the order of 5KB, and is adjusted from time to
|
||||||
time, taking as a reference being able to access https://google.com .
|
time, taking as a reference being able to access https://google.com .
|
||||||
The smaller buffer hower means that some sites can't be accessed using
|
The smaller buffer however means that some sites can't be accessed using
|
||||||
it, and it's not possible to stream large amounts of data.
|
it, and it's not possible to stream large amounts of data. axTLS does
|
||||||
|
have support for TLS's Max Fragment Size extension, but no HTTPS website
|
||||||
|
does, so use of the extension is really only effective for local
|
||||||
|
communication with other devices.
|
||||||
|
|
||||||
There are also some not implemented features specifically in MicroPython's
|
There are also some not implemented features specifically in MicroPython's
|
||||||
``ussl`` module based on axTLS:
|
``ussl`` module based on axTLS:
|
||||||
|
|
||||||
6. Certificates are not validated (this may make connections susceptible
|
6. Certificates are not validated (this makes connections susceptible
|
||||||
to man-in-the-middle attacks).
|
to man-in-the-middle attacks).
|
||||||
7. There is no support for client certificates (scheduled to be fixed in
|
7. There is no support for client certificates (scheduled to be fixed in
|
||||||
1.9.4 release).
|
1.9.4 release).
|
||||||
|
|||||||
@ -58,7 +58,7 @@ The :mod:`network` module::
|
|||||||
wlan.scan() # scan for access points
|
wlan.scan() # scan for access points
|
||||||
wlan.isconnected() # check if the station is connected to an AP
|
wlan.isconnected() # check if the station is connected to an AP
|
||||||
wlan.connect('essid', 'password') # connect to an AP
|
wlan.connect('essid', 'password') # connect to an AP
|
||||||
wlan.config('mac') # get the interface's MAC adddress
|
wlan.config('mac') # get the interface's MAC address
|
||||||
wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses
|
wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses
|
||||||
|
|
||||||
ap = network.WLAN(network.AP_IF) # create access-point interface
|
ap = network.WLAN(network.AP_IF) # create access-point interface
|
||||||
@ -138,6 +138,10 @@ Also note that Pin(16) is a special pin (used for wakeup from deepsleep
|
|||||||
mode) and may be not available for use with higher-level classes like
|
mode) and may be not available for use with higher-level classes like
|
||||||
``Neopixel``.
|
``Neopixel``.
|
||||||
|
|
||||||
|
There's a higher-level abstraction :ref:`machine.Signal <machine.Signal>`
|
||||||
|
which can be used to invert a pin. Useful for illuminating active-low LEDs
|
||||||
|
using ``on()`` or ``value(1)``.
|
||||||
|
|
||||||
UART (serial bus)
|
UART (serial bus)
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
@ -293,6 +297,17 @@ See :ref:`machine.RTC <machine.RTC>` ::
|
|||||||
(using a custom handler), `RTC.init()` and `RTC.deinit()` are
|
(using a custom handler), `RTC.init()` and `RTC.deinit()` are
|
||||||
currently not supported.
|
currently not supported.
|
||||||
|
|
||||||
|
WDT (Watchdog timer)
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
See :ref:`machine.WDT <machine.WDT>`. ::
|
||||||
|
|
||||||
|
from machine import WDT
|
||||||
|
|
||||||
|
# enable the WDT
|
||||||
|
wdt = WDT()
|
||||||
|
wdt.feed()
|
||||||
|
|
||||||
Deep-sleep mode
|
Deep-sleep mode
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@ -409,6 +424,20 @@ The DHT driver is implemented in software and works on all pins::
|
|||||||
d.temperature() # eg. 23.6 (°C)
|
d.temperature() # eg. 23.6 (°C)
|
||||||
d.humidity() # eg. 41.3 (% RH)
|
d.humidity() # eg. 41.3 (% RH)
|
||||||
|
|
||||||
|
SSD1306 driver
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Driver for SSD1306 monochrome OLED displays. See tutorial :ref:`ssd1306`. ::
|
||||||
|
|
||||||
|
from machine import Pin, I2C
|
||||||
|
import ssd1306
|
||||||
|
|
||||||
|
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)
|
||||||
|
display = ssd1306.SSD1306_I2C(128, 64, i2c)
|
||||||
|
|
||||||
|
display.text('Hello World', 0, 0, 1)
|
||||||
|
display.show()
|
||||||
|
|
||||||
WebREPL (web browser interactive prompt)
|
WebREPL (web browser interactive prompt)
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
|
|||||||
@ -31,4 +31,5 @@ to `<https://www.python.org>`__.
|
|||||||
neopixel.rst
|
neopixel.rst
|
||||||
apa102.rst
|
apa102.rst
|
||||||
dht.rst
|
dht.rst
|
||||||
|
ssd1306.rst
|
||||||
nextsteps.rst
|
nextsteps.rst
|
||||||
|
|||||||
@ -75,6 +75,10 @@ the DTR and RTS pins wired in a special way then deploying the firmware should
|
|||||||
be easy as all steps can be done automatically. Boards that have such features
|
be easy as all steps can be done automatically. Boards that have such features
|
||||||
include the Adafruit Feather HUZZAH and NodeMCU boards.
|
include the Adafruit Feather HUZZAH and NodeMCU boards.
|
||||||
|
|
||||||
|
If you do not have such a board, you need keep GPIO0 pulled to ground and reset
|
||||||
|
the device by pulling the reset pin to ground and releasing it again to enter
|
||||||
|
programming mode.
|
||||||
|
|
||||||
For best results it is recommended to first erase the entire flash of your
|
For best results it is recommended to first erase the entire flash of your
|
||||||
device before putting on new MicroPython firmware.
|
device before putting on new MicroPython firmware.
|
||||||
|
|
||||||
@ -113,6 +117,10 @@ the firmware (note the ``-fm dio`` option)::
|
|||||||
If the above commands run without error then MicroPython should be installed on
|
If the above commands run without error then MicroPython should be installed on
|
||||||
your board!
|
your board!
|
||||||
|
|
||||||
|
If you pulled GPIO0 manually to ground to enter programming mode, release it
|
||||||
|
now and reset the device by again pulling the reset pin to ground for a short
|
||||||
|
duration.
|
||||||
|
|
||||||
Serial prompt
|
Serial prompt
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|||||||
93
docs/esp8266/tutorial/ssd1306.rst
Normal file
93
docs/esp8266/tutorial/ssd1306.rst
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
.. _ssd1306:
|
||||||
|
|
||||||
|
Using a SSD1306 OLED display
|
||||||
|
============================
|
||||||
|
|
||||||
|
The SSD1306 OLED display uses either a SPI or I2C interface and comes in a variety of
|
||||||
|
sizes (128x64, 128x32, 72x40, 64x48) and colours (white, yellow, blue, yellow + blue).
|
||||||
|
|
||||||
|
Hardware SPI interface::
|
||||||
|
|
||||||
|
from machine import Pin, SPI
|
||||||
|
import ssd1306
|
||||||
|
|
||||||
|
hspi = SPI(1) # sck=14 (scl), mosi=13 (sda), miso=12 (unused)
|
||||||
|
|
||||||
|
dc = Pin(4) # data/command
|
||||||
|
rst = Pin(5) # reset
|
||||||
|
cs = Pin(15) # chip select, some modules do not have a pin for this
|
||||||
|
|
||||||
|
display = ssd1306.SSD1306_SPI(128, 64, hspi, dc, rst, cs)
|
||||||
|
|
||||||
|
Software SPI interface::
|
||||||
|
|
||||||
|
from machine import Pin, SoftSPI
|
||||||
|
import ssd1306
|
||||||
|
|
||||||
|
spi = SoftSPI(baudrate=500000, polarity=1, phase=0, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
|
||||||
|
|
||||||
|
dc = Pin(4) # data/command
|
||||||
|
rst = Pin(5) # reset
|
||||||
|
cs = Pin(15) # chip select, some modules do not have a pin for this
|
||||||
|
|
||||||
|
display = ssd1306.SSD1306_SPI(128, 64, spi, dc, rst, cs)
|
||||||
|
|
||||||
|
I2C interface::
|
||||||
|
|
||||||
|
from machine import Pin, I2C
|
||||||
|
import ssd1306
|
||||||
|
|
||||||
|
# using default address 0x3C
|
||||||
|
i2c = I2C(sda=Pin(4), scl=Pin(5))
|
||||||
|
display = ssd1306.SSD1306_I2C(128, 64, i2c)
|
||||||
|
|
||||||
|
Print Hello World on the first line::
|
||||||
|
|
||||||
|
display.text('Hello, World!', 0, 0, 1)
|
||||||
|
display.show()
|
||||||
|
|
||||||
|
Basic functions::
|
||||||
|
|
||||||
|
display.poweroff() # power off the display, pixels persist in memory
|
||||||
|
display.poweron() # power on the display, pixels redrawn
|
||||||
|
display.contrast(0) # dim
|
||||||
|
display.contrast(255) # bright
|
||||||
|
display.invert(1) # display inverted
|
||||||
|
display.invert(0) # display normal
|
||||||
|
display.rotate(True) # rotate 180 degrees
|
||||||
|
display.rotate(False) # rotate 0 degrees
|
||||||
|
display.show() # write the contents of the FrameBuffer to display memory
|
||||||
|
|
||||||
|
Subclassing FrameBuffer provides support for graphics primitives::
|
||||||
|
|
||||||
|
display.fill(0) # fill entire screen with colour=0
|
||||||
|
display.pixel(0, 10) # get pixel at x=0, y=10
|
||||||
|
display.pixel(0, 10, 1) # set pixel at x=0, y=10 to colour=1
|
||||||
|
display.hline(0, 8, 4, 1) # draw horizontal line x=0, y=8, width=4, colour=1
|
||||||
|
display.vline(0, 8, 4, 1) # draw vertical line x=0, y=8, height=4, colour=1
|
||||||
|
display.line(0, 0, 127, 63, 1) # draw a line from 0,0 to 127,63
|
||||||
|
display.rect(10, 10, 107, 43, 1) # draw a rectangle outline 10,10 to 107,43, colour=1
|
||||||
|
display.fill_rect(10, 10, 107, 43, 1) # draw a solid rectangle 10,10 to 107,43, colour=1
|
||||||
|
display.text('Hello World', 0, 0, 1) # draw some text at x=0, y=0, colour=1
|
||||||
|
display.scroll(20, 0) # scroll 20 pixels to the right
|
||||||
|
|
||||||
|
# draw another FrameBuffer on top of the current one at the given coordinates
|
||||||
|
import framebuf
|
||||||
|
fbuf = framebuf.FrameBuffer(bytearray(8 * 8 * 1), 8, 8, framebuf.MONO_VLSB)
|
||||||
|
fbuf.line(0, 0, 7, 7, 1)
|
||||||
|
display.blit(fbuf, 10, 10, 0) # draw on top at x=10, y=10, key=0
|
||||||
|
display.show()
|
||||||
|
|
||||||
|
Draw the MicroPython logo and print some text::
|
||||||
|
|
||||||
|
display.fill(0)
|
||||||
|
display.fill_rect(0, 0, 32, 32, 1)
|
||||||
|
display.fill_rect(2, 2, 28, 28, 0)
|
||||||
|
display.vline(9, 8, 22, 1)
|
||||||
|
display.vline(16, 2, 22, 1)
|
||||||
|
display.vline(23, 8, 22, 1)
|
||||||
|
display.fill_rect(26, 24, 2, 4, 1)
|
||||||
|
display.text('MicroPython', 40, 0, 1)
|
||||||
|
display.text('SSD1306', 40, 12, 1)
|
||||||
|
display.text('OLED 128x64', 40, 24, 1)
|
||||||
|
display.show()
|
||||||
@ -11,5 +11,6 @@ MicroPython documentation and references
|
|||||||
pyboard/quickref.rst
|
pyboard/quickref.rst
|
||||||
esp8266/quickref.rst
|
esp8266/quickref.rst
|
||||||
esp32/quickref.rst
|
esp32/quickref.rst
|
||||||
|
rp2/quickref.rst
|
||||||
wipy/quickref.rst
|
wipy/quickref.rst
|
||||||
unix/quickref.rst
|
unix/quickref.rst
|
||||||
|
|||||||
@ -176,10 +176,6 @@ Exceptions
|
|||||||
|
|
||||||
.. exception:: OSError
|
.. exception:: OSError
|
||||||
|
|
||||||
|see_cpython| `python:OSError`. MicroPython doesn't implement ``errno``
|
|
||||||
attribute, instead use the standard way to access exception arguments:
|
|
||||||
``exc.args[0]``.
|
|
||||||
|
|
||||||
.. exception:: RuntimeError
|
.. exception:: RuntimeError
|
||||||
|
|
||||||
.. exception:: StopIteration
|
.. exception:: StopIteration
|
||||||
|
|||||||
@ -162,7 +162,7 @@ used to transmit or receive many other types of digital signals::
|
|||||||
The input to the RMT module is an 80MHz clock (in the future it may be able to
|
The input to the RMT module is an 80MHz clock (in the future it may be able to
|
||||||
configure the input clock but, for now, it's fixed). ``clock_div`` *divides*
|
configure the input clock but, for now, it's fixed). ``clock_div`` *divides*
|
||||||
the clock input which determines the resolution of the RMT channel. The
|
the clock input which determines the resolution of the RMT channel. The
|
||||||
numbers specificed in ``write_pulses`` are multiplied by the resolution to
|
numbers specified in ``write_pulses`` are multiplied by the resolution to
|
||||||
define the pulses.
|
define the pulses.
|
||||||
|
|
||||||
``clock_div`` is an 8-bit divider (0-255) and each pulse can be defined by
|
``clock_div`` is an 8-bit divider (0-255) and each pulse can be defined by
|
||||||
|
|||||||
@ -165,3 +165,14 @@ The following libraries are specific to the ESP8266 and ESP32.
|
|||||||
|
|
||||||
esp.rst
|
esp.rst
|
||||||
esp32.rst
|
esp32.rst
|
||||||
|
|
||||||
|
|
||||||
|
Libraries specific to the RP2040
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
The following libraries are specific to the RP2040, as used in the Raspberry Pi Pico.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
rp2.rst
|
||||||
|
|||||||
79
docs/library/machine.PWM.rst
Normal file
79
docs/library/machine.PWM.rst
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
.. currentmodule:: machine
|
||||||
|
.. _machine.PWM:
|
||||||
|
|
||||||
|
class PWM -- pulse width modulation
|
||||||
|
===================================
|
||||||
|
|
||||||
|
This class provides pulse width modulation output.
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
from machine import PWM
|
||||||
|
|
||||||
|
pwm = PWM(pin) # create a PWM object on a pin
|
||||||
|
pwm.duty_u16(32768) # set duty to 50%
|
||||||
|
|
||||||
|
# reinitialise with a period of 200us, duty of 5us
|
||||||
|
pwm.init(freq=5000, duty_ns=5000)
|
||||||
|
|
||||||
|
pwm.duty_ns(3000) # set pulse width to 3us
|
||||||
|
|
||||||
|
pwm.deinit()
|
||||||
|
|
||||||
|
Constructors
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. class:: PWM(dest, \*, freq, duty_u16, duty_ns)
|
||||||
|
|
||||||
|
Construct and return a new PWM object using the following parameters:
|
||||||
|
|
||||||
|
- *dest* is the entity on which the PWM is output, which is usually a
|
||||||
|
:ref:`machine.Pin <machine.Pin>` object, but a port may allow other values,
|
||||||
|
like integers.
|
||||||
|
- *freq* should be an integer which sets the frequency in Hz for the
|
||||||
|
PWM cycle.
|
||||||
|
- *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``.
|
||||||
|
- *duty_ns* sets the pulse width in nanoseconds.
|
||||||
|
|
||||||
|
Setting *freq* may affect other PWM objects if the objects share the same
|
||||||
|
underlying PWM generator (this is hardware specific).
|
||||||
|
Only one of *duty_u16* and *duty_ns* should be specified at a time.
|
||||||
|
|
||||||
|
Methods
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. method:: PWM.init(\*, freq, duty_u16, duty_ns)
|
||||||
|
|
||||||
|
Modify settings for the PWM object. See the above constructor for details
|
||||||
|
about the parameters.
|
||||||
|
|
||||||
|
.. method:: PWM.deinit()
|
||||||
|
|
||||||
|
Disable the PWM output.
|
||||||
|
|
||||||
|
.. method:: PWM.freq([value])
|
||||||
|
|
||||||
|
Get or set the current frequency of the PWM output.
|
||||||
|
|
||||||
|
With no arguments the frequency in Hz is returned.
|
||||||
|
|
||||||
|
With a single *value* argument the frequency is set to that value in Hz. The
|
||||||
|
method may raise a ``ValueError`` if the frequency is outside the valid range.
|
||||||
|
|
||||||
|
.. method:: PWM.duty_u16([value])
|
||||||
|
|
||||||
|
Get or set the current duty cycle of the PWM output, as an unsigned 16-bit
|
||||||
|
value in the range 0 to 65535 inclusive.
|
||||||
|
|
||||||
|
With no arguments the duty cycle is returned.
|
||||||
|
|
||||||
|
With a single *value* argument the duty cycle is set to that value, measured
|
||||||
|
as the ratio ``value / 65535``.
|
||||||
|
|
||||||
|
.. method:: PWM.duty_ns([value])
|
||||||
|
|
||||||
|
Get or set the current pulse width of the PWM output, as a value in nanoseconds.
|
||||||
|
|
||||||
|
With no arguments the pulse width in nanoseconds is returned.
|
||||||
|
|
||||||
|
With a single *value* argument the pulse width is set to that value.
|
||||||
@ -9,7 +9,7 @@ the most flexible and heterogeneous kind of hardware in MCUs and SoCs,
|
|||||||
differently greatly from a model to a model. MicroPython's Timer class
|
differently greatly from a model to a model. MicroPython's Timer class
|
||||||
defines a baseline operation of executing a callback with a given period
|
defines a baseline operation of executing a callback with a given period
|
||||||
(or once after some delay), and allow specific boards to define more
|
(or once after some delay), and allow specific boards to define more
|
||||||
non-standard behavior (which thus won't be portable to other boards).
|
non-standard behaviour (which thus won't be portable to other boards).
|
||||||
|
|
||||||
See discussion of :ref:`important constraints <machine_callbacks>` on
|
See discussion of :ref:`important constraints <machine_callbacks>` on
|
||||||
Timer callbacks.
|
Timer callbacks.
|
||||||
|
|||||||
@ -16,7 +16,7 @@ the most flexible and heterogeneous kind of hardware in MCUs and SoCs,
|
|||||||
differently greatly from a model to a model. MicroPython's Timer class
|
differently greatly from a model to a model. MicroPython's Timer class
|
||||||
defines a baseline operation of executing a callback with a given period
|
defines a baseline operation of executing a callback with a given period
|
||||||
(or once after some delay), and allow specific boards to define more
|
(or once after some delay), and allow specific boards to define more
|
||||||
non-standard behavior (which thus won't be portable to other boards).
|
non-standard behaviour (which thus won't be portable to other boards).
|
||||||
|
|
||||||
See discussion of :ref:`important constraints <machine_callbacks>` on
|
See discussion of :ref:`important constraints <machine_callbacks>` on
|
||||||
Timer callbacks.
|
Timer callbacks.
|
||||||
@ -115,7 +115,7 @@ Methods
|
|||||||
|
|
||||||
.. method:: timerchannel.irq(*, trigger, priority=1, handler=None)
|
.. method:: timerchannel.irq(*, trigger, priority=1, handler=None)
|
||||||
|
|
||||||
The behavior of this callback is heavily dependent on the operating
|
The behaviour of this callback is heavily dependent on the operating
|
||||||
mode of the timer channel:
|
mode of the timer channel:
|
||||||
|
|
||||||
- If mode is ``TimerWiPy.PERIODIC`` the callback is executed periodically
|
- If mode is ``TimerWiPy.PERIODIC`` the callback is executed periodically
|
||||||
|
|||||||
@ -37,6 +37,14 @@ Reset related functions
|
|||||||
|
|
||||||
Get the reset cause. See :ref:`constants <machine_constants>` for the possible return values.
|
Get the reset cause. See :ref:`constants <machine_constants>` for the possible return values.
|
||||||
|
|
||||||
|
.. function:: bootloader([value])
|
||||||
|
|
||||||
|
Reset the device and enter its bootloader. This is typically used to put the
|
||||||
|
device into a state where it can be programmed with new firmware.
|
||||||
|
|
||||||
|
Some ports support passing in an optional *value* argument which can control
|
||||||
|
which bootloader to enter, what to pass to it, or other things.
|
||||||
|
|
||||||
Interrupt related functions
|
Interrupt related functions
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
@ -56,9 +64,11 @@ Interrupt related functions
|
|||||||
Power related functions
|
Power related functions
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
.. function:: freq()
|
.. function:: freq([hz])
|
||||||
|
|
||||||
Returns CPU frequency in hertz.
|
Returns the CPU frequency in hertz.
|
||||||
|
|
||||||
|
On some ports this can also be used to set the CPU frequency by passing in *hz*.
|
||||||
|
|
||||||
.. function:: idle()
|
.. function:: idle()
|
||||||
|
|
||||||
@ -167,6 +177,7 @@ Classes
|
|||||||
machine.Pin.rst
|
machine.Pin.rst
|
||||||
machine.Signal.rst
|
machine.Signal.rst
|
||||||
machine.ADC.rst
|
machine.ADC.rst
|
||||||
|
machine.PWM.rst
|
||||||
machine.UART.rst
|
machine.UART.rst
|
||||||
machine.SPI.rst
|
machine.SPI.rst
|
||||||
machine.I2C.rst
|
machine.I2C.rst
|
||||||
|
|||||||
@ -25,7 +25,7 @@ For this example to work the CC3000 module must have the following connections:
|
|||||||
- VBEN connected to Y4
|
- VBEN connected to Y4
|
||||||
- IRQ connected to Y3
|
- IRQ connected to Y3
|
||||||
|
|
||||||
It is possible to use other SPI busses and other pins for CS, VBEN and IRQ.
|
It is possible to use other SPI buses and other pins for CS, VBEN and IRQ.
|
||||||
|
|
||||||
Constructors
|
Constructors
|
||||||
------------
|
------------
|
||||||
|
|||||||
@ -26,7 +26,7 @@ For this example to work the WIZnet5x00 module must have the following connectio
|
|||||||
- nSS connected to X5
|
- nSS connected to X5
|
||||||
- nRESET connected to X4
|
- nRESET connected to X4
|
||||||
|
|
||||||
It is possible to use other SPI busses and other pins for nSS and nRESET.
|
It is possible to use other SPI buses and other pins for nSS and nRESET.
|
||||||
|
|
||||||
Constructors
|
Constructors
|
||||||
------------
|
------------
|
||||||
|
|||||||
@ -55,7 +55,7 @@ parameter should be `id`.
|
|||||||
Activate ("up") or deactivate ("down") the network interface, if
|
Activate ("up") or deactivate ("down") the network interface, if
|
||||||
a boolean argument is passed. Otherwise, query current state if
|
a boolean argument is passed. Otherwise, query current state if
|
||||||
no argument is provided. Most other methods require an active
|
no argument is provided. Most other methods require an active
|
||||||
interface (behavior of calling them on inactive interface is
|
interface (behaviour of calling them on inactive interface is
|
||||||
undefined).
|
undefined).
|
||||||
|
|
||||||
.. method:: AbstractNIC.connect([service_id, key=None, *, ...])
|
.. method:: AbstractNIC.connect([service_id, key=None, *, ...])
|
||||||
|
|||||||
@ -30,7 +30,7 @@ Constructors
|
|||||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||||
See :meth:`CAN.init` for parameters of initialisation.
|
See :meth:`CAN.init` for parameters of initialisation.
|
||||||
|
|
||||||
The physical pins of the CAN busses are:
|
The physical pins of the CAN buses are:
|
||||||
|
|
||||||
- ``CAN(1)`` is on ``YA``: ``(RX, TX) = (Y3, Y4) = (PB8, PB9)``
|
- ``CAN(1)`` is on ``YA``: ``(RX, TX) = (Y3, Y4) = (PB8, PB9)``
|
||||||
- ``CAN(2)`` is on ``YB``: ``(RX, TX) = (Y5, Y6) = (PB12, PB13)``
|
- ``CAN(2)`` is on ``YB``: ``(RX, TX) = (Y5, Y6) = (PB12, PB13)``
|
||||||
|
|||||||
@ -64,7 +64,7 @@ Constructors
|
|||||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||||
See ``init`` for parameters of initialisation.
|
See ``init`` for parameters of initialisation.
|
||||||
|
|
||||||
The physical pins of the I2C busses on Pyboards V1.0 and V1.1 are:
|
The physical pins of the I2C buses on Pyboards V1.0 and V1.1 are:
|
||||||
|
|
||||||
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
|
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
|
||||||
- ``I2C(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)``
|
- ``I2C(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)``
|
||||||
|
|||||||
@ -98,11 +98,11 @@ Class methods
|
|||||||
Methods
|
Methods
|
||||||
-------
|
-------
|
||||||
|
|
||||||
.. method:: Pin.init(mode, pull=Pin.PULL_NONE, af=-1)
|
.. method:: Pin.init(mode, pull=Pin.PULL_NONE, \*, value=None, alt=-1)
|
||||||
|
|
||||||
Initialise the pin:
|
Initialise the pin:
|
||||||
|
|
||||||
- ``mode`` can be one of:
|
- *mode* can be one of:
|
||||||
|
|
||||||
- ``Pin.IN`` - configure the pin for input;
|
- ``Pin.IN`` - configure the pin for input;
|
||||||
- ``Pin.OUT_PP`` - configure the pin for output, with push-pull control;
|
- ``Pin.OUT_PP`` - configure the pin for output, with push-pull control;
|
||||||
@ -111,14 +111,17 @@ Methods
|
|||||||
- ``Pin.AF_OD`` - configure the pin for alternate function, open-drain;
|
- ``Pin.AF_OD`` - configure the pin for alternate function, open-drain;
|
||||||
- ``Pin.ANALOG`` - configure the pin for analog.
|
- ``Pin.ANALOG`` - configure the pin for analog.
|
||||||
|
|
||||||
- ``pull`` can be one of:
|
- *pull* can be one of:
|
||||||
|
|
||||||
- ``Pin.PULL_NONE`` - no pull up or down resistors;
|
- ``Pin.PULL_NONE`` - no pull up or down resistors;
|
||||||
- ``Pin.PULL_UP`` - enable the pull-up resistor;
|
- ``Pin.PULL_UP`` - enable the pull-up resistor;
|
||||||
- ``Pin.PULL_DOWN`` - enable the pull-down resistor.
|
- ``Pin.PULL_DOWN`` - enable the pull-down resistor.
|
||||||
|
|
||||||
- when mode is ``Pin.AF_PP`` or ``Pin.AF_OD``, then af can be the index or name
|
- *value* if not None will set the port output value before enabling the pin.
|
||||||
of one of the alternate functions associated with a pin.
|
|
||||||
|
- *alt* can be used when mode is ``Pin.AF_PP`` or ``Pin.AF_OD`` to set the
|
||||||
|
index or name of one of the alternate functions associated with a pin.
|
||||||
|
This arg was previously called *af* which can still be used if needed.
|
||||||
|
|
||||||
Returns: ``None``.
|
Returns: ``None``.
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ Constructors
|
|||||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||||
See ``init`` for parameters of initialisation.
|
See ``init`` for parameters of initialisation.
|
||||||
|
|
||||||
The physical pins of the SPI busses are:
|
The physical pins of the SPI buses are:
|
||||||
|
|
||||||
- ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)``
|
- ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)``
|
||||||
- ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)``
|
- ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)``
|
||||||
|
|||||||
@ -57,7 +57,7 @@ Constructors
|
|||||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||||
See ``init`` for parameters of initialisation.
|
See ``init`` for parameters of initialisation.
|
||||||
|
|
||||||
The physical pins of the UART busses on Pyboard are:
|
The physical pins of the UART buses on Pyboard are:
|
||||||
|
|
||||||
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
|
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
|
||||||
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
|
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
|
||||||
|
|||||||
@ -126,7 +126,7 @@ Power related functions
|
|||||||
- pclk2: frequency of the APB2 bus
|
- pclk2: frequency of the APB2 bus
|
||||||
|
|
||||||
If given any arguments then the function sets the frequency of the CPU,
|
If given any arguments then the function sets the frequency of the CPU,
|
||||||
and the busses if additional arguments are given. Frequencies are given in
|
and the buses if additional arguments are given. Frequencies are given in
|
||||||
Hz. Eg freq(120000000) sets sysclk (the CPU frequency) to 120MHz. Note that
|
Hz. Eg freq(120000000) sets sysclk (the CPU frequency) to 120MHz. Note that
|
||||||
not all values are supported and the largest supported frequency not greater
|
not all values are supported and the largest supported frequency not greater
|
||||||
than the given value will be selected.
|
than the given value will be selected.
|
||||||
|
|||||||
36
docs/library/rp2.Flash.rst
Normal file
36
docs/library/rp2.Flash.rst
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
.. currentmodule:: rp2
|
||||||
|
.. _rp2.Flash:
|
||||||
|
|
||||||
|
class Flash -- access to built-in flash storage
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
This class gives access to the SPI flash memory.
|
||||||
|
|
||||||
|
In most cases, to store persistent data on the device, you'll want to use a
|
||||||
|
higher-level abstraction, for example the filesystem via Python's standard file
|
||||||
|
API, but this interface is useful to :ref:`customise the filesystem
|
||||||
|
configuration <filesystem>` or implement a low-level storage system for your
|
||||||
|
application.
|
||||||
|
|
||||||
|
|
||||||
|
Constructors
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. class:: Flash()
|
||||||
|
|
||||||
|
Gets the singleton object for accessing the SPI flash memory.
|
||||||
|
|
||||||
|
|
||||||
|
Methods
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. method:: Flash.readblocks(block_num, buf)
|
||||||
|
Flash.readblocks(block_num, buf, offset)
|
||||||
|
.. method:: Flash.writeblocks(block_num, buf)
|
||||||
|
Flash.writeblocks(block_num, buf, offset)
|
||||||
|
.. method:: Flash.ioctl(cmd, arg)
|
||||||
|
|
||||||
|
These methods implement the simple and extended
|
||||||
|
:ref:`block protocol <block-device-interface>` defined by
|
||||||
|
:class:`uos.AbstractBlockDev`.
|
||||||
|
|
||||||
94
docs/library/rp2.PIO.rst
Normal file
94
docs/library/rp2.PIO.rst
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
.. currentmodule:: rp2
|
||||||
|
.. _rp2.PIO:
|
||||||
|
|
||||||
|
class PIO -- advanced PIO usage
|
||||||
|
===============================
|
||||||
|
|
||||||
|
The :class:`PIO` class gives access to an instance of the RP2040's PIO
|
||||||
|
(programmable I/O) interface.
|
||||||
|
|
||||||
|
The preferred way to interact with PIO is using :class:`rp2.StateMachine`, the
|
||||||
|
PIO class is for advanced use.
|
||||||
|
|
||||||
|
For assembling PIO programs, see :func:`rp2.asm_pio`.
|
||||||
|
|
||||||
|
|
||||||
|
Constructors
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. class:: PIO(id)
|
||||||
|
|
||||||
|
Gets the PIO instance numbered *id*. The RP2040 has two PIO instances,
|
||||||
|
numbered 0 and 1.
|
||||||
|
|
||||||
|
Raises a ``ValueError`` if any other argument is provided.
|
||||||
|
|
||||||
|
|
||||||
|
Methods
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. method:: PIO.add_program(program)
|
||||||
|
|
||||||
|
Add the *program* to the instruction memory of this PIO instance.
|
||||||
|
|
||||||
|
The amount of memory available for programs on each PIO instance is
|
||||||
|
limited. If there isn't enough space left in the PIO's program memory
|
||||||
|
this method will raise ``OSError(ENOMEM)``.
|
||||||
|
|
||||||
|
.. method:: PIO.remove_program([program])
|
||||||
|
|
||||||
|
Remove *program* from the instruction memory of this PIO instance.
|
||||||
|
|
||||||
|
If no program is provided, it removes all programs.
|
||||||
|
|
||||||
|
It is not an error to remove a program which has already been removed.
|
||||||
|
|
||||||
|
.. method:: PIO.state_machine(id, [program, ...])
|
||||||
|
|
||||||
|
Gets the state machine numbered *id*. On the RP2040, each PIO instance has
|
||||||
|
four state machines, numbered 0 to 3.
|
||||||
|
|
||||||
|
Optionally initialize it with a *program*: see `StateMachine.init`.
|
||||||
|
|
||||||
|
>>> rp2.PIO(1).state_machine(3)
|
||||||
|
StateMachine(7)
|
||||||
|
|
||||||
|
.. method:: PIO.irq(handler=None, trigger=IRQ_SM0|IRQ_SM1|IRQ_SM2|IRQ_SM3, hard=False)
|
||||||
|
|
||||||
|
Returns the IRQ object for this PIO instance.
|
||||||
|
|
||||||
|
MicroPython only uses IRQ 0 on each PIO instance. IRQ 1 is not available.
|
||||||
|
|
||||||
|
Optionally configure it.
|
||||||
|
|
||||||
|
|
||||||
|
Constants
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. data:: PIO.IN_LOW
|
||||||
|
PIO.IN_HIGH
|
||||||
|
PIO.OUT_LOW
|
||||||
|
PIO.OUT_HIGH
|
||||||
|
|
||||||
|
These constants are used for the *out_init*, *set_init*, and *sideset_init*
|
||||||
|
arguments to `asm_pio`.
|
||||||
|
|
||||||
|
.. data:: PIO.SHIFT_LEFT
|
||||||
|
PIO.SHIFT_RIGHT
|
||||||
|
|
||||||
|
These constants are used for the *in_shiftdir* and *out_shiftdir* arguments
|
||||||
|
to `asm_pio` or `StateMachine.init`.
|
||||||
|
|
||||||
|
.. data:: PIO.JOIN_NONE
|
||||||
|
PIO.JOIN_TX
|
||||||
|
PIO.JOIN_RX
|
||||||
|
|
||||||
|
These constants are used for the *fifo_join* argument to `asm_pio`.
|
||||||
|
|
||||||
|
.. data:: PIO.IRQ_SM0
|
||||||
|
PIO.IRQ_SM1
|
||||||
|
PIO.IRQ_SM2
|
||||||
|
PIO.IRQ_SM3
|
||||||
|
|
||||||
|
These constants are used for the *trigger* argument to `PIO.irq`.
|
||||||
|
|
||||||
131
docs/library/rp2.StateMachine.rst
Normal file
131
docs/library/rp2.StateMachine.rst
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
.. currentmodule:: rp2
|
||||||
|
.. _rp2.StateMachine:
|
||||||
|
|
||||||
|
class StateMachine -- access to the RP2040's programmable I/O interface
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
The :class:`StateMachine` class gives access to the RP2040's PIO (programmable
|
||||||
|
I/O) interface.
|
||||||
|
|
||||||
|
For assembling PIO programs, see :func:`rp2.asm_pio`.
|
||||||
|
|
||||||
|
|
||||||
|
Constructors
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. class:: StateMachine(id, [program, ...])
|
||||||
|
|
||||||
|
Get the state machine numbered *id*. The RP2040 has two identical PIO
|
||||||
|
instances, each with 4 state machines: so there are 8 state machines in
|
||||||
|
total, numbered 0 to 7.
|
||||||
|
|
||||||
|
Optionally initialize it with the given program *program*: see
|
||||||
|
`StateMachine.init`.
|
||||||
|
|
||||||
|
|
||||||
|
Methods
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. method:: StateMachine.init(program, freq=-1, *, in_base=None, out_base=None, set_base=None, jmp_pin=None, sideset_base=None, in_shiftdir=None, out_shiftdir=None, push_thresh=None, pull_thresh=None)
|
||||||
|
|
||||||
|
Configure the state machine instance to run the given *program*.
|
||||||
|
|
||||||
|
The program is added to the instruction memory of this PIO instance. If the
|
||||||
|
instruction memory already contains this program, then its offset is
|
||||||
|
re-used so as to save on instruction memory.
|
||||||
|
|
||||||
|
- *freq* is the frequency in Hz to run the state machine at. Defaults to
|
||||||
|
the system clock frequency.
|
||||||
|
|
||||||
|
The clock divider is computed as ``system clock frequency / freq``, so
|
||||||
|
there can be slight rounding errors.
|
||||||
|
|
||||||
|
The minimum possible clock divider is one 65536th of the system clock: so
|
||||||
|
at the default system clock frequency of 125MHz, the minimum value of
|
||||||
|
*freq* is ``1908``. To run state machines at slower frequencies, you'll
|
||||||
|
need to reduce the system clock speed with `machine.freq()`.
|
||||||
|
- *in_base* is the first pin to use for ``in()`` instructions.
|
||||||
|
- *out_base* is the first pin to use for ``out()`` instructions.
|
||||||
|
- *set_base* is the first pin to use for ``set()`` instructions.
|
||||||
|
- *jmp_pin* is the first pin to use for ``jmp(pin, ...)`` instructions.
|
||||||
|
- *sideset_base* is the first pin to use for side-setting.
|
||||||
|
- *in_shiftdir* is the direction the ISR will shift, either
|
||||||
|
`PIO.SHIFT_LEFT` or `PIO.SHIFT_RIGHT`.
|
||||||
|
- *out_shiftdir* is the direction the OSR will shift, either
|
||||||
|
`PIO.SHIFT_LEFT` or `PIO.SHIFT_RIGHT`.
|
||||||
|
- *push_thresh* is the threshold in bits before auto-push or conditional
|
||||||
|
re-pushing is triggered.
|
||||||
|
- *pull_thresh* is the threshold in bits before auto-push or conditional
|
||||||
|
re-pushing is triggered.
|
||||||
|
|
||||||
|
.. method:: StateMachine.active([value])
|
||||||
|
|
||||||
|
Gets or sets whether the state machine is currently running.
|
||||||
|
|
||||||
|
>>> sm.active()
|
||||||
|
True
|
||||||
|
>>> sm.active(0)
|
||||||
|
False
|
||||||
|
|
||||||
|
.. method:: StateMachine.restart()
|
||||||
|
|
||||||
|
Restarts the state machine and jumps to the beginning of the program.
|
||||||
|
|
||||||
|
This method clears the state machine's internal state using the RP2040's
|
||||||
|
``SM_RESTART`` register. This includes:
|
||||||
|
|
||||||
|
- input and output shift counters
|
||||||
|
- the contents of the input shift register
|
||||||
|
- the delay counter
|
||||||
|
- the waiting-on-IRQ state
|
||||||
|
- a stalled instruction run using `StateMachine.exec()`
|
||||||
|
|
||||||
|
.. method:: StateMachine.exec(instr)
|
||||||
|
|
||||||
|
Execute a single PIO instruction. Uses `asm_pio_encode` to encode the
|
||||||
|
instruction from the given string *instr*.
|
||||||
|
|
||||||
|
>>> sm.exec("set(0, 1)")
|
||||||
|
|
||||||
|
.. method:: StateMachine.get(buf=None, shift=0)
|
||||||
|
|
||||||
|
Pull a word from the state machine's RX FIFO.
|
||||||
|
|
||||||
|
If the FIFO is empty, it blocks until data arrives (i.e. the state machine
|
||||||
|
pushes a word).
|
||||||
|
|
||||||
|
The value is shifted right by *shift* bits before returning, i.e. the
|
||||||
|
return value is ``word >> shift``.
|
||||||
|
|
||||||
|
.. method:: StateMachine.put(value, shift=0)
|
||||||
|
|
||||||
|
Push a word onto the state machine's TX FIFO.
|
||||||
|
|
||||||
|
If the FIFO is full, it blocks until there is space (i.e. the state machine
|
||||||
|
pulls a word).
|
||||||
|
|
||||||
|
The value is first shifted left by *shift* bits, i.e. the state machine
|
||||||
|
receives ``value << shift``.
|
||||||
|
|
||||||
|
.. method:: StateMachine.rx_fifo()
|
||||||
|
|
||||||
|
Returns the number of words in the state machine's RX FIFO. A value of 0
|
||||||
|
indicates the FIFO is empty.
|
||||||
|
|
||||||
|
Useful for checking if data is waiting to be read, before calling
|
||||||
|
`StateMachine.get()`.
|
||||||
|
|
||||||
|
.. method:: StateMachine.tx_fifo()
|
||||||
|
|
||||||
|
Returns the number of words in the state machine's TX FIFO. A value of 0
|
||||||
|
indicates the FIFO is empty.
|
||||||
|
|
||||||
|
Useful for checking if there is space to push another word using
|
||||||
|
`StateMachine.put()`.
|
||||||
|
|
||||||
|
.. method:: StateMachine.irq(handler=None, trigger=0|1, hard=False)
|
||||||
|
|
||||||
|
Returns the IRQ object for the given StateMachine.
|
||||||
|
|
||||||
|
Optionally configure it.
|
||||||
|
|
||||||
83
docs/library/rp2.rst
Normal file
83
docs/library/rp2.rst
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
.. currentmodule:: rp2
|
||||||
|
|
||||||
|
:mod:`rp2` --- functionality specific to the RP2040
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
.. module:: rp2
|
||||||
|
:synopsis: functionality specific to the RP2
|
||||||
|
|
||||||
|
The ``rp2`` module contains functions and classes specific to the RP2040, as
|
||||||
|
used in the Raspberry Pi Pico.
|
||||||
|
|
||||||
|
See the `RP2040 Python datasheet
|
||||||
|
<https://datasheets.raspberrypi.org/pico/raspberry-pi-pico-python-sdk.pdf>`_
|
||||||
|
for more information, and `pico-micropython-examples
|
||||||
|
<https://github.com/raspberrypi/pico-micropython-examples/tree/master/pio>`_
|
||||||
|
for example code.
|
||||||
|
|
||||||
|
|
||||||
|
PIO related functions
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The ``rp2`` module includes functions for assembling PIO programs.
|
||||||
|
|
||||||
|
For running PIO programs, see :class:`rp2.StateMachine`.
|
||||||
|
|
||||||
|
.. function:: asm_pio(*, out_init=None, set_init=None, sideset_init=None, in_shiftdir=0, out_shiftdir=0, autopush=False, autopull=False, push_thresh=32, pull_thresh=32, fifo_join=PIO.JOIN_NONE)
|
||||||
|
|
||||||
|
Assemble a PIO program.
|
||||||
|
|
||||||
|
The following parameters control the initial state of the GPIO pins, as one
|
||||||
|
of `PIO.IN_LOW`, `PIO.IN_HIGH`, `PIO.OUT_LOW` or `PIO.OUT_HIGH`. If the
|
||||||
|
program uses more than one pin, provide a tuple, e.g.
|
||||||
|
``out_init=(PIO.OUT_LOW, PIO.OUT_LOW)``.
|
||||||
|
|
||||||
|
- *out_init* configures the pins used for ``out()`` instructions.
|
||||||
|
- *set_init* configures the pins used for ``set()`` instructions. There can
|
||||||
|
be at most 5.
|
||||||
|
- *sideset_init* configures the pins used side-setting. There can be at
|
||||||
|
most 5.
|
||||||
|
|
||||||
|
The following parameters are used by default, but can be overridden in
|
||||||
|
`StateMachine.init()`:
|
||||||
|
|
||||||
|
- *in_shiftdir* is the default direction the ISR will shift, either
|
||||||
|
`PIO.SHIFT_LEFT` or `PIO.SHIFT_RIGHT`.
|
||||||
|
- *out_shiftdir* is the default direction the OSR will shift, either
|
||||||
|
`PIO.SHIFT_LEFT` or `PIO.SHIFT_RIGHT`.
|
||||||
|
- *push_thresh* is the threshold in bits before auto-push or conditional
|
||||||
|
re-pushing is triggered.
|
||||||
|
- *pull_thresh* is the threshold in bits before auto-push or conditional
|
||||||
|
re-pushing is triggered.
|
||||||
|
|
||||||
|
The remaining parameters are:
|
||||||
|
|
||||||
|
- *autopush* configures whether auto-push is enabled.
|
||||||
|
- *autopull* configures whether auto-pull is enabled.
|
||||||
|
- *fifo_join* configures whether the 4-word TX and RX FIFOs should be
|
||||||
|
combined into a single 8-word FIFO for one direction only. The options
|
||||||
|
are `PIO.JOIN_NONE`, `PIO.JOIN_RX` and `PIO.JOIN_TX`.
|
||||||
|
|
||||||
|
.. function:: asm_pio_encode(instr, sideset_count)
|
||||||
|
|
||||||
|
Assemble a single PIO instruction. You usually want to use `asm_pio()`
|
||||||
|
instead.
|
||||||
|
|
||||||
|
>>> rp2.asm_pio_encode("set(0, 1)", 0)
|
||||||
|
57345
|
||||||
|
|
||||||
|
.. class:: PIOASMError
|
||||||
|
|
||||||
|
This exception is raised from `asm_pio()` or `asm_pio_encode()` if there is
|
||||||
|
an error assembling a PIO program.
|
||||||
|
|
||||||
|
|
||||||
|
Classes
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
rp2.Flash.rst
|
||||||
|
rp2.PIO.rst
|
||||||
|
rp2.StateMachine.rst
|
||||||
@ -245,7 +245,7 @@ Module contents
|
|||||||
|
|
||||||
.. data:: VOID
|
.. data:: VOID
|
||||||
|
|
||||||
``VOID`` is an alias for ``UINT8``, and is provided to conviniently define
|
``VOID`` is an alias for ``UINT8``, and is provided to conveniently define
|
||||||
C's void pointers: ``(uctypes.PTR, uctypes.VOID)``.
|
C's void pointers: ``(uctypes.PTR, uctypes.VOID)``.
|
||||||
|
|
||||||
.. data:: PTR
|
.. data:: PTR
|
||||||
|
|||||||
@ -16,13 +16,13 @@ Constants
|
|||||||
|
|
||||||
Error codes, based on ANSI C/POSIX standard. All error codes start with
|
Error codes, based on ANSI C/POSIX standard. All error codes start with
|
||||||
"E". As mentioned above, inventory of the codes depends on
|
"E". As mentioned above, inventory of the codes depends on
|
||||||
:term:`MicroPython port`. Errors are usually accessible as ``exc.args[0]``
|
:term:`MicroPython port`. Errors are usually accessible as ``exc.errno``
|
||||||
where ``exc`` is an instance of `OSError`. Usage example::
|
where ``exc`` is an instance of `OSError`. Usage example::
|
||||||
|
|
||||||
try:
|
try:
|
||||||
uos.mkdir("my_dir")
|
uos.mkdir("my_dir")
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
if exc.args[0] == uerrno.EEXIST:
|
if exc.errno == uerrno.EEXIST:
|
||||||
print("Directory already exists")
|
print("Directory already exists")
|
||||||
|
|
||||||
.. data:: errorcode
|
.. data:: errorcode
|
||||||
|
|||||||
@ -6,9 +6,11 @@
|
|||||||
|
|
||||||
|see_cpython_module| :mod:`python:heapq`.
|
|see_cpython_module| :mod:`python:heapq`.
|
||||||
|
|
||||||
This module implements the heap queue algorithm.
|
This module implements the
|
||||||
|
`min heap queue algorithm <https://en.wikipedia.org/wiki/Heap_%28data_structure%29>`_.
|
||||||
|
|
||||||
A heap queue is simply a list that has its elements stored in a certain way.
|
A heap queue is essentially a list that has its elements stored in such a way
|
||||||
|
that the first item of the list is always the smallest.
|
||||||
|
|
||||||
Functions
|
Functions
|
||||||
---------
|
---------
|
||||||
@ -19,8 +21,10 @@ Functions
|
|||||||
|
|
||||||
.. function:: heappop(heap)
|
.. function:: heappop(heap)
|
||||||
|
|
||||||
Pop the first item from the ``heap``, and return it. Raises IndexError if
|
Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if
|
||||||
heap is empty.
|
``heap`` is empty.
|
||||||
|
|
||||||
|
The returned item will be the smallest item in the ``heap``.
|
||||||
|
|
||||||
.. function:: heapify(x)
|
.. function:: heapify(x)
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ Conceptual hierarchy
|
|||||||
Conceptual hierarchy of stream base classes is simplified in MicroPython,
|
Conceptual hierarchy of stream base classes is simplified in MicroPython,
|
||||||
as described in this section.
|
as described in this section.
|
||||||
|
|
||||||
(Abstract) base stream classes, which serve as a foundation for behavior
|
(Abstract) base stream classes, which serve as a foundation for behaviour
|
||||||
of all the concrete classes, adhere to few dichotomies (pair-wise
|
of all the concrete classes, adhere to few dichotomies (pair-wise
|
||||||
classifications) in CPython. In MicroPython, they are somewhat simplified
|
classifications) in CPython. In MicroPython, they are somewhat simplified
|
||||||
and made implicit to achieve higher efficiencies and save resources.
|
and made implicit to achieve higher efficiencies and save resources.
|
||||||
@ -41,15 +41,15 @@ more concise and efficient programs - something which is highly desirable
|
|||||||
for MicroPython. So, while MicroPython doesn't support buffered streams,
|
for MicroPython. So, while MicroPython doesn't support buffered streams,
|
||||||
it still provides for no-short-operations streams. Whether there will
|
it still provides for no-short-operations streams. Whether there will
|
||||||
be short operations or not depends on each particular class' needs, but
|
be short operations or not depends on each particular class' needs, but
|
||||||
developers are strongly advised to favor no-short-operations behavior
|
developers are strongly advised to favour no-short-operations behaviour
|
||||||
for the reasons stated above. For example, MicroPython sockets are
|
for the reasons stated above. For example, MicroPython sockets are
|
||||||
guaranteed to avoid short read/writes. Actually, at this time, there is
|
guaranteed to avoid short read/writes. Actually, at this time, there is
|
||||||
no example of a short-operations stream class in the core, and one would
|
no example of a short-operations stream class in the core, and one would
|
||||||
be a port-specific class, where such a need is governed by hardware
|
be a port-specific class, where such a need is governed by hardware
|
||||||
peculiarities.
|
peculiarities.
|
||||||
|
|
||||||
The no-short-operations behavior gets tricky in case of non-blocking
|
The no-short-operations behaviour gets tricky in case of non-blocking
|
||||||
streams, blocking vs non-blocking behavior being another CPython dichotomy,
|
streams, blocking vs non-blocking behaviour being another CPython dichotomy,
|
||||||
fully supported by MicroPython. Non-blocking streams never wait for
|
fully supported by MicroPython. Non-blocking streams never wait for
|
||||||
data either to arrive or be written - they read/write whatever possible,
|
data either to arrive or be written - they read/write whatever possible,
|
||||||
or signal lack of data (or ability to write data). Clearly, this conflicts
|
or signal lack of data (or ability to write data). Clearly, this conflicts
|
||||||
|
|||||||
@ -87,11 +87,11 @@ Methods
|
|||||||
`callee-owned tuple`. This function provides an efficient, allocation-free
|
`callee-owned tuple`. This function provides an efficient, allocation-free
|
||||||
way to poll on streams.
|
way to poll on streams.
|
||||||
|
|
||||||
If *flags* is 1, one-shot behavior for events is employed: streams for
|
If *flags* is 1, one-shot behaviour for events is employed: streams for
|
||||||
which events happened will have their event masks automatically reset
|
which events happened will have their event masks automatically reset
|
||||||
(equivalent to ``poll.modify(obj, 0)``), so new events for such a stream
|
(equivalent to ``poll.modify(obj, 0)``), so new events for such a stream
|
||||||
won't be processed until new mask is set with `poll.modify()`. This
|
won't be processed until new mask is set with `poll.modify()`. This
|
||||||
behavior is useful for asynchronous I/O schedulers.
|
behaviour is useful for asynchronous I/O schedulers.
|
||||||
|
|
||||||
.. admonition:: Difference to CPython
|
.. admonition:: Difference to CPython
|
||||||
:class: attention
|
:class: attention
|
||||||
|
|||||||
@ -222,7 +222,7 @@ Methods
|
|||||||
Unlike `send()`, this method will try to send all of data, by sending data
|
Unlike `send()`, this method will try to send all of data, by sending data
|
||||||
chunk by chunk consecutively.
|
chunk by chunk consecutively.
|
||||||
|
|
||||||
The behavior of this method on non-blocking sockets is undefined. Due to this,
|
The behaviour of this method on non-blocking sockets is undefined. Due to this,
|
||||||
on MicroPython, it's recommended to use `write()` method instead, which
|
on MicroPython, it's recommended to use `write()` method instead, which
|
||||||
has the same "no short writes" policy for blocking sockets, and will return
|
has the same "no short writes" policy for blocking sockets, and will return
|
||||||
number of bytes sent on non-blocking sockets.
|
number of bytes sent on non-blocking sockets.
|
||||||
|
|||||||
@ -13,7 +13,8 @@ facilities for network sockets, both client-side and server-side.
|
|||||||
Functions
|
Functions
|
||||||
---------
|
---------
|
||||||
|
|
||||||
.. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None, do_handshake=True)
|
.. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None, do_handshake=True)
|
||||||
|
|
||||||
Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type),
|
Takes a `stream` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type),
|
||||||
and returns an instance of ssl.SSLSocket, which wraps the underlying stream in
|
and returns an instance of ssl.SSLSocket, which wraps the underlying stream in
|
||||||
an SSL context. Returned object has the usual `stream` interface methods like
|
an SSL context. Returned object has the usual `stream` interface methods like
|
||||||
|
|||||||
@ -173,7 +173,7 @@ Functions
|
|||||||
long sleep), then once you finally look again, it may seem to you that only 1 hour
|
long sleep), then once you finally look again, it may seem to you that only 1 hour
|
||||||
has passed. To avoid this mistake, just look at the clock regularly. Your application
|
has passed. To avoid this mistake, just look at the clock regularly. Your application
|
||||||
should do the same. "Too long sleep" metaphor also maps directly to application
|
should do the same. "Too long sleep" metaphor also maps directly to application
|
||||||
behavior: don't let your application run any single task for too long. Run tasks
|
behaviour: don't let your application run any single task for too long. Run tasks
|
||||||
in steps, and do time-keeping inbetween.
|
in steps, and do time-keeping inbetween.
|
||||||
|
|
||||||
`ticks_diff()` is designed to accommodate various usage patterns, among them:
|
`ticks_diff()` is designed to accommodate various usage patterns, among them:
|
||||||
|
|||||||
@ -93,7 +93,7 @@ on the pin for any changes, and the following will occur:
|
|||||||
running Python script.
|
running Python script.
|
||||||
3. The microcontroller starts executing the special interrupt handler
|
3. The microcontroller starts executing the special interrupt handler
|
||||||
associated with the switch's external trigger. This interrupt handler
|
associated with the switch's external trigger. This interrupt handler
|
||||||
get the function that you registered with ``sw.callback()`` and executes
|
gets the function that you registered with ``sw.callback()`` and executes
|
||||||
it.
|
it.
|
||||||
4. Your callback function is executed until it finishes, returning control
|
4. Your callback function is executed until it finishes, returning control
|
||||||
to the switch interrupt handler.
|
to the switch interrupt handler.
|
||||||
|
|||||||
18
docs/rp2/general.rst
Normal file
18
docs/rp2/general.rst
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
.. _rp2_general:
|
||||||
|
|
||||||
|
General information about the RP2xxx port
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
The rp2 port supports boards powered by the Raspberry Pi Foundation's RP2xxx
|
||||||
|
family of microcontrollers, most notably the Raspberry Pi Pico that employs
|
||||||
|
the RP2040.
|
||||||
|
|
||||||
|
Technical specifications and SoC datasheets
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
Datasheets!
|
||||||
|
|
||||||
|
Short summary of tech specs!
|
||||||
|
|
||||||
|
Description of general structure of the port (it's built on top of the APIs
|
||||||
|
provided by the Raspberry Pi SDK).
|
||||||
BIN
docs/rp2/img/rpipico.jpg
Normal file
BIN
docs/rp2/img/rpipico.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
288
docs/rp2/quickref.rst
Normal file
288
docs/rp2/quickref.rst
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
.. _rp2_quickref:
|
||||||
|
|
||||||
|
Quick reference for the RP2
|
||||||
|
===========================
|
||||||
|
|
||||||
|
.. image:: img/rpipico.jpg
|
||||||
|
:alt: Raspberry Pi Pico
|
||||||
|
:width: 640px
|
||||||
|
|
||||||
|
The Raspberry Pi Pico Development Board (image attribution: Raspberry Pi Foundation).
|
||||||
|
|
||||||
|
Below is a quick reference for Raspberry Pi RP2xxx boards. If it is your first time
|
||||||
|
working with this board it may be useful to get an overview of the microcontroller:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
general.rst
|
||||||
|
tutorial/intro.rst
|
||||||
|
|
||||||
|
Installing MicroPython
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
See the corresponding section of tutorial: :ref:`rp2_intro`. It also includes
|
||||||
|
a troubleshooting subsection.
|
||||||
|
|
||||||
|
General board control
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The MicroPython REPL is on the USB serial port.
|
||||||
|
Tab-completion is useful to find out what methods an object has.
|
||||||
|
Paste mode (ctrl-E) is useful to paste a large slab of Python code into
|
||||||
|
the REPL.
|
||||||
|
|
||||||
|
The :mod:`machine` module::
|
||||||
|
|
||||||
|
import machine
|
||||||
|
|
||||||
|
machine.freq() # get the current frequency of the CPU
|
||||||
|
machine.freq(240000000) # set the CPU frequency to 240 MHz
|
||||||
|
|
||||||
|
The :mod:`rp2` module::
|
||||||
|
|
||||||
|
import rp2
|
||||||
|
|
||||||
|
Delay and timing
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Use the :mod:`time <utime>` module::
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
time.sleep(1) # sleep for 1 second
|
||||||
|
time.sleep_ms(500) # sleep for 500 milliseconds
|
||||||
|
time.sleep_us(10) # sleep for 10 microseconds
|
||||||
|
start = time.ticks_ms() # get millisecond counter
|
||||||
|
delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference
|
||||||
|
|
||||||
|
Timers
|
||||||
|
------
|
||||||
|
|
||||||
|
How do they work?
|
||||||
|
|
||||||
|
.. _rp2_Pins_and_GPIO:
|
||||||
|
|
||||||
|
Pins and GPIO
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Use the :ref:`machine.Pin <machine.Pin>` class::
|
||||||
|
|
||||||
|
from machine import Pin
|
||||||
|
|
||||||
|
p0 = Pin(0, Pin.OUT) # create output pin on GPIO0
|
||||||
|
p0.on() # set pin to "on" (high) level
|
||||||
|
p0.off() # set pin to "off" (low) level
|
||||||
|
p0.value(1) # set pin to on/high
|
||||||
|
|
||||||
|
p2 = Pin(2, Pin.IN) # create input pin on GPIO2
|
||||||
|
print(p2.value()) # get value, 0 or 1
|
||||||
|
|
||||||
|
p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor
|
||||||
|
p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation
|
||||||
|
|
||||||
|
UART (serial bus)
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
See :ref:`machine.UART <machine.UART>`. ::
|
||||||
|
|
||||||
|
from machine import UART
|
||||||
|
|
||||||
|
uart1 = UART(1, baudrate=9600, tx=33, rx=32)
|
||||||
|
uart1.write('hello') # write 5 bytes
|
||||||
|
uart1.read(5) # read up to 5 bytes
|
||||||
|
|
||||||
|
|
||||||
|
PWM (pulse width modulation)
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
How does PWM work on the RPi RP2xxx?
|
||||||
|
|
||||||
|
Use the ``machine.PWM`` class::
|
||||||
|
|
||||||
|
from machine import Pin, PWM
|
||||||
|
|
||||||
|
pwm0 = PWM(Pin(0)) # create PWM object from a pin
|
||||||
|
pwm0.freq() # get current frequency
|
||||||
|
pwm0.freq(1000) # set frequency
|
||||||
|
pwm0.duty_u16() # get current duty cycle, range 0-65535
|
||||||
|
pwm0.duty_u16(200) # set duty cycle, range 0-65535
|
||||||
|
pwm0.deinit() # turn off PWM on the pin
|
||||||
|
|
||||||
|
ADC (analog to digital conversion)
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
How does the ADC module work?
|
||||||
|
|
||||||
|
Use the :ref:`machine.ADC <machine.ADC>` class::
|
||||||
|
|
||||||
|
from machine import ADC
|
||||||
|
|
||||||
|
adc = ADC(Pin(32)) # create ADC object on ADC pin
|
||||||
|
adc.read_u16() # read value, 0-65535 across voltage range 0.0v - 3.3v
|
||||||
|
|
||||||
|
Software SPI bus
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Software SPI (using bit-banging) works on all pins, and is accessed via the
|
||||||
|
:ref:`machine.SoftSPI <machine.SoftSPI>` class::
|
||||||
|
|
||||||
|
from machine import Pin, SoftSPI
|
||||||
|
|
||||||
|
# construct a SoftSPI bus on the given pins
|
||||||
|
# polarity is the idle state of SCK
|
||||||
|
# phase=0 means sample on the first edge of SCK, phase=1 means the second
|
||||||
|
spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||||
|
|
||||||
|
spi.init(baudrate=200000) # set the baudrate
|
||||||
|
|
||||||
|
spi.read(10) # read 10 bytes on MISO
|
||||||
|
spi.read(10, 0xff) # read 10 bytes while outputting 0xff on MOSI
|
||||||
|
|
||||||
|
buf = bytearray(50) # create a buffer
|
||||||
|
spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case)
|
||||||
|
spi.readinto(buf, 0xff) # read into the given buffer and output 0xff on MOSI
|
||||||
|
|
||||||
|
spi.write(b'12345') # write 5 bytes on MOSI
|
||||||
|
|
||||||
|
buf = bytearray(4) # create a buffer
|
||||||
|
spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer
|
||||||
|
spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf
|
||||||
|
|
||||||
|
.. Warning::
|
||||||
|
Currently *all* of ``sck``, ``mosi`` and ``miso`` *must* be specified when
|
||||||
|
initialising Software SPI.
|
||||||
|
|
||||||
|
Hardware SPI bus
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Hardware SPI is accessed via the :ref:`machine.SPI <machine.SPI>` class and
|
||||||
|
has the same methods as software SPI above::
|
||||||
|
|
||||||
|
from machine import Pin, SPI
|
||||||
|
|
||||||
|
spi = SPI(1, 10000000)
|
||||||
|
spi = SPI(1, 10000000, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
|
||||||
|
spi = SPI(2, baudrate=80000000, polarity=0, phase=0, bits=8, firstbit=0, sck=Pin(18), mosi=Pin(23), miso=Pin(19))
|
||||||
|
|
||||||
|
Software I2C bus
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Software I2C (using bit-banging) works on all output-capable pins, and is
|
||||||
|
accessed via the :ref:`machine.SoftI2C <machine.SoftI2C>` class::
|
||||||
|
|
||||||
|
from machine import Pin, SoftI2C
|
||||||
|
|
||||||
|
i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000)
|
||||||
|
|
||||||
|
i2c.scan() # scan for devices
|
||||||
|
|
||||||
|
i2c.readfrom(0x3a, 4) # read 4 bytes from device with address 0x3a
|
||||||
|
i2c.writeto(0x3a, '12') # write '12' to device with address 0x3a
|
||||||
|
|
||||||
|
buf = bytearray(10) # create a buffer with 10 bytes
|
||||||
|
i2c.writeto(0x3a, buf) # write the given buffer to the slave
|
||||||
|
|
||||||
|
Hardware I2C bus
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The driver is accessed via the :ref:`machine.I2C <machine.I2C>` class and
|
||||||
|
has the same methods as software I2C above::
|
||||||
|
|
||||||
|
from machine import Pin, I2C
|
||||||
|
|
||||||
|
i2c = I2C(0)
|
||||||
|
i2c = I2C(1, scl=Pin(5), sda=Pin(4), freq=400000)
|
||||||
|
|
||||||
|
Real time clock (RTC)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
See :ref:`machine.RTC <machine.RTC>` ::
|
||||||
|
|
||||||
|
from machine import RTC
|
||||||
|
|
||||||
|
rtc = RTC()
|
||||||
|
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time
|
||||||
|
rtc.datetime() # get date and time
|
||||||
|
|
||||||
|
WDT (Watchdog timer)
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Is there a watchdog timer?
|
||||||
|
|
||||||
|
See :ref:`machine.WDT <machine.WDT>`. ::
|
||||||
|
|
||||||
|
from machine import WDT
|
||||||
|
|
||||||
|
# enable the WDT with a timeout of 5s (1s is the minimum)
|
||||||
|
wdt = WDT(timeout=5000)
|
||||||
|
wdt.feed()
|
||||||
|
|
||||||
|
Deep-sleep mode
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Is there deep-sleep support for the rp2?
|
||||||
|
|
||||||
|
The following code can be used to sleep, wake and check the reset cause::
|
||||||
|
|
||||||
|
import machine
|
||||||
|
|
||||||
|
# check if the device woke from a deep sleep
|
||||||
|
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
|
||||||
|
print('woke from a deep sleep')
|
||||||
|
|
||||||
|
# put the device to sleep for 10 seconds
|
||||||
|
machine.deepsleep(10000)
|
||||||
|
|
||||||
|
OneWire driver
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The OneWire driver is implemented in software and works on all pins::
|
||||||
|
|
||||||
|
from machine import Pin
|
||||||
|
import onewire
|
||||||
|
|
||||||
|
ow = onewire.OneWire(Pin(12)) # create a OneWire bus on GPIO12
|
||||||
|
ow.scan() # return a list of devices on the bus
|
||||||
|
ow.reset() # reset the bus
|
||||||
|
ow.readbyte() # read a byte
|
||||||
|
ow.writebyte(0x12) # write a byte on the bus
|
||||||
|
ow.write('123') # write bytes on the bus
|
||||||
|
ow.select_rom(b'12345678') # select a specific device by its ROM code
|
||||||
|
|
||||||
|
There is a specific driver for DS18S20 and DS18B20 devices::
|
||||||
|
|
||||||
|
import time, ds18x20
|
||||||
|
ds = ds18x20.DS18X20(ow)
|
||||||
|
roms = ds.scan()
|
||||||
|
ds.convert_temp()
|
||||||
|
time.sleep_ms(750)
|
||||||
|
for rom in roms:
|
||||||
|
print(ds.read_temp(rom))
|
||||||
|
|
||||||
|
Be sure to put a 4.7k pull-up resistor on the data line. Note that
|
||||||
|
the ``convert_temp()`` method must be called each time you want to
|
||||||
|
sample the temperature.
|
||||||
|
|
||||||
|
NeoPixel and APA106 driver
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Use the ``neopixel`` and ``apa106`` modules::
|
||||||
|
|
||||||
|
from machine import Pin
|
||||||
|
from neopixel import NeoPixel
|
||||||
|
|
||||||
|
pin = Pin(0, Pin.OUT) # set GPIO0 to output to drive NeoPixels
|
||||||
|
np = NeoPixel(pin, 8) # create NeoPixel driver on GPIO0 for 8 pixels
|
||||||
|
np[0] = (255, 255, 255) # set the first pixel to white
|
||||||
|
np.write() # write data to all pixels
|
||||||
|
r, g, b = np[0] # get first pixel colour
|
||||||
|
|
||||||
|
|
||||||
|
The APA106 driver extends NeoPixel, but internally uses a different colour order::
|
||||||
|
|
||||||
|
from apa106 import APA106
|
||||||
|
ap = APA106(pin, 8)
|
||||||
|
r, g, b = ap[0]
|
||||||
|
|
||||||
|
APA102 (DotStar) uses a different driver as it has an additional clock pin.
|
||||||
6
docs/rp2/tutorial/intro.rst
Normal file
6
docs/rp2/tutorial/intro.rst
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.. _rp2_intro:
|
||||||
|
|
||||||
|
Getting started with MicroPython on the RP2xxx
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
Let's get started!
|
||||||
4
docs/templates/topindex.html
vendored
4
docs/templates/topindex.html
vendored
@ -58,6 +58,10 @@
|
|||||||
<a class="biglink" href="{{ pathto("esp32/quickref") }}">Quick reference for the ESP32</a><br/>
|
<a class="biglink" href="{{ pathto("esp32/quickref") }}">Quick reference for the ESP32</a><br/>
|
||||||
<span class="linkdescr">pinout for ESP32-based boards, snippets of useful code, and a tutorial</span>
|
<span class="linkdescr">pinout for ESP32-based boards, snippets of useful code, and a tutorial</span>
|
||||||
</p>
|
</p>
|
||||||
|
<p class="biglink">
|
||||||
|
<a class="biglink" href="{{ pathto("rp2/quickref") }}">Quick reference for the Raspberry Pi RP2xxx</a><br/>
|
||||||
|
<span class="linkdescr">pinout for rp2xxx-based boards, snippets of useful code, and a tutorial</span>
|
||||||
|
</p>
|
||||||
<p class="biglink">
|
<p class="biglink">
|
||||||
<a class="biglink" href="{{ pathto("wipy/quickref") }}">Quick reference for the WiPy/CC3200</a><br/>
|
<a class="biglink" href="{{ pathto("wipy/quickref") }}">Quick reference for the WiPy/CC3200</a><br/>
|
||||||
<span class="linkdescr">pinout for the WiPy/CC3200, snippets of useful code, and a tutorial</span>
|
<span class="linkdescr">pinout for the WiPy/CC3200, snippets of useful code, and a tutorial</span>
|
||||||
|
|||||||
@ -112,7 +112,7 @@ void cyw43_deinit(cyw43_t *self) {
|
|||||||
self->itf_state = 0;
|
self->itf_state = 0;
|
||||||
|
|
||||||
// Disable async polling
|
// Disable async polling
|
||||||
SDMMC1->MASK &= ~SDMMC_MASK_SDIOITIE;
|
sdio_enable_irq(false);
|
||||||
cyw43_poll = NULL;
|
cyw43_poll = NULL;
|
||||||
|
|
||||||
#ifdef pyb_pin_WL_RFSW_VDD
|
#ifdef pyb_pin_WL_RFSW_VDD
|
||||||
@ -164,7 +164,7 @@ STATIC int cyw43_ensure_up(cyw43_t *self) {
|
|||||||
cyw43_sleep = CYW43_SLEEP_MAX;
|
cyw43_sleep = CYW43_SLEEP_MAX;
|
||||||
cyw43_poll = cyw43_poll_func;
|
cyw43_poll = cyw43_poll_func;
|
||||||
#if USE_SDIOIT
|
#if USE_SDIOIT
|
||||||
SDMMC1->MASK |= SDMMC_MASK_SDIOITIE;
|
sdio_enable_irq(true);
|
||||||
#else
|
#else
|
||||||
extern void extint_set(const pin_obj_t *pin, uint32_t mode);
|
extern void extint_set(const pin_obj_t *pin, uint32_t mode);
|
||||||
extint_set(pyb_pin_WL_HOST_WAKE, GPIO_MODE_IT_FALLING);
|
extint_set(pyb_pin_WL_HOST_WAKE, GPIO_MODE_IT_FALLING);
|
||||||
@ -209,7 +209,7 @@ STATIC void cyw43_poll_func(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if USE_SDIOIT
|
#if USE_SDIOIT
|
||||||
SDMMC1->MASK |= SDMMC_MASK_SDIOITIE;
|
sdio_enable_irq(true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,10 +227,7 @@ int cyw43_cb_read_host_interrupt_pin(void *cb_data) {
|
|||||||
void cyw43_cb_ensure_awake(void *cb_data) {
|
void cyw43_cb_ensure_awake(void *cb_data) {
|
||||||
cyw43_sleep = CYW43_SLEEP_MAX;
|
cyw43_sleep = CYW43_SLEEP_MAX;
|
||||||
#if !USE_SDIOIT
|
#if !USE_SDIOIT
|
||||||
if (__HAL_RCC_SDMMC1_IS_CLK_DISABLED()) {
|
sdio_reenable();
|
||||||
__HAL_RCC_SDMMC1_CLK_ENABLE(); // enable SDIO peripheral
|
|
||||||
sdio_enable_high_speed_4bit();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,7 @@ STATIC void cywbt_wait_cts_low(void) {
|
|||||||
}
|
}
|
||||||
mp_hal_delay_ms(1);
|
mp_hal_delay_ms(1);
|
||||||
}
|
}
|
||||||
mp_hal_pin_config_alt_static(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_USART6_CTS);
|
mp_hal_pin_config_alt(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_UART, mp_bluetooth_hci_uart_obj.uart_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
||||||
@ -149,10 +149,14 @@ STATIC int cywbt_download_firmware(const uint8_t *firmware) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RF switch must select high path during BT patch boot
|
// RF switch must select high path during BT patch boot
|
||||||
|
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||||
mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
|
mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
|
||||||
|
#endif
|
||||||
mp_hal_delay_ms(10); // give some time for CTS to go high
|
mp_hal_delay_ms(10); // give some time for CTS to go high
|
||||||
cywbt_wait_cts_low();
|
cywbt_wait_cts_low();
|
||||||
|
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||||
mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0); // Select chip antenna (could also select external)
|
mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0); // Select chip antenna (could also select external)
|
||||||
|
#endif
|
||||||
|
|
||||||
mp_bluetooth_hci_uart_set_baudrate(115200);
|
mp_bluetooth_hci_uart_set_baudrate(115200);
|
||||||
cywbt_set_baudrate(3000000);
|
cywbt_set_baudrate(3000000);
|
||||||
@ -170,9 +174,11 @@ int mp_bluetooth_hci_controller_init(void) {
|
|||||||
mp_hal_pin_output(pyb_pin_BT_DEV_WAKE);
|
mp_hal_pin_output(pyb_pin_BT_DEV_WAKE);
|
||||||
mp_hal_pin_low(pyb_pin_BT_DEV_WAKE);
|
mp_hal_pin_low(pyb_pin_BT_DEV_WAKE);
|
||||||
|
|
||||||
|
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||||
// TODO don't select antenna if wifi is enabled
|
// TODO don't select antenna if wifi is enabled
|
||||||
mp_hal_pin_config(pyb_pin_WL_GPIO_4, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power
|
mp_hal_pin_config(pyb_pin_WL_GPIO_4, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power
|
||||||
mp_hal_pin_high(pyb_pin_WL_GPIO_4); // Turn the RF-switch on
|
mp_hal_pin_high(pyb_pin_WL_GPIO_4); // Turn the RF-switch on
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t buf[256];
|
uint8_t buf[256];
|
||||||
|
|
||||||
|
|||||||
@ -37,12 +37,12 @@ class SSD1306(framebuf.FrameBuffer):
|
|||||||
|
|
||||||
def init_display(self):
|
def init_display(self):
|
||||||
for cmd in (
|
for cmd in (
|
||||||
SET_DISP | 0x00, # off
|
SET_DISP, # display off
|
||||||
# address setting
|
# address setting
|
||||||
SET_MEM_ADDR,
|
SET_MEM_ADDR,
|
||||||
0x00, # horizontal
|
0x00, # horizontal
|
||||||
# resolution and layout
|
# resolution and layout
|
||||||
SET_DISP_START_LINE | 0x00,
|
SET_DISP_START_LINE, # start at line 0
|
||||||
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
|
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
|
||||||
SET_MUX_RATIO,
|
SET_MUX_RATIO,
|
||||||
self.height - 1,
|
self.height - 1,
|
||||||
@ -66,14 +66,14 @@ class SSD1306(framebuf.FrameBuffer):
|
|||||||
# charge pump
|
# charge pump
|
||||||
SET_CHARGE_PUMP,
|
SET_CHARGE_PUMP,
|
||||||
0x10 if self.external_vcc else 0x14,
|
0x10 if self.external_vcc else 0x14,
|
||||||
SET_DISP | 0x01,
|
SET_DISP | 0x01, # display on
|
||||||
): # on
|
): # on
|
||||||
self.write_cmd(cmd)
|
self.write_cmd(cmd)
|
||||||
self.fill(0)
|
self.fill(0)
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def poweroff(self):
|
def poweroff(self):
|
||||||
self.write_cmd(SET_DISP | 0x00)
|
self.write_cmd(SET_DISP)
|
||||||
|
|
||||||
def poweron(self):
|
def poweron(self):
|
||||||
self.write_cmd(SET_DISP | 0x01)
|
self.write_cmd(SET_DISP | 0x01)
|
||||||
@ -85,6 +85,10 @@ class SSD1306(framebuf.FrameBuffer):
|
|||||||
def invert(self, invert):
|
def invert(self, invert):
|
||||||
self.write_cmd(SET_NORM_INV | (invert & 1))
|
self.write_cmd(SET_NORM_INV | (invert & 1))
|
||||||
|
|
||||||
|
def rotate(self, rotate):
|
||||||
|
self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3))
|
||||||
|
self.write_cmd(SET_SEG_REMAP | (rotate & 1))
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
x0 = 0
|
x0 = 0
|
||||||
x1 = self.width - 1
|
x1 = self.width - 1
|
||||||
|
|||||||
@ -176,6 +176,7 @@ class SDCard:
|
|||||||
self.spi.readinto(self.tokenbuf, 0xFF)
|
self.spi.readinto(self.tokenbuf, 0xFF)
|
||||||
if self.tokenbuf[0] == _TOKEN_DATA:
|
if self.tokenbuf[0] == _TOKEN_DATA:
|
||||||
break
|
break
|
||||||
|
time.sleep_ms(1)
|
||||||
else:
|
else:
|
||||||
self.cs(1)
|
self.cs(1)
|
||||||
raise OSError("timeout waiting for response")
|
raise OSError("timeout waiting for response")
|
||||||
|
|||||||
@ -34,38 +34,10 @@
|
|||||||
|
|
||||||
#if MICROPY_PY_UCTYPES
|
#if MICROPY_PY_UCTYPES
|
||||||
|
|
||||||
/// \module uctypes - Access data structures in memory
|
// The uctypes module allows defining the layout of a raw data structure (using
|
||||||
///
|
// terms of the C language), and then access memory buffers using this definition.
|
||||||
/// The module allows to define layout of raw data structure (using terms
|
// The module also provides convenience functions to access memory buffers
|
||||||
/// of C language), and then access memory buffers using this definition.
|
// contained in Python objects or wrap memory buffers in Python objects.
|
||||||
/// The module also provides convenience functions to access memory buffers
|
|
||||||
/// contained in Python objects or wrap memory buffers in Python objects.
|
|
||||||
/// \constant UINT8_1 - uint8_t value type
|
|
||||||
|
|
||||||
/// \class struct - C-like structure
|
|
||||||
///
|
|
||||||
/// Encapsulalation of in-memory data structure. This class doesn't define
|
|
||||||
/// any methods, only attribute access (for structure fields) and
|
|
||||||
/// indexing (for pointer and array fields).
|
|
||||||
///
|
|
||||||
/// Usage:
|
|
||||||
///
|
|
||||||
/// # Define layout of a structure with 2 fields
|
|
||||||
/// # 0 and 4 are byte offsets of fields from the beginning of struct
|
|
||||||
/// # they are logically ORed with field type
|
|
||||||
/// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8}
|
|
||||||
///
|
|
||||||
/// # Example memory buffer to access (contained in bytes object)
|
|
||||||
/// buf = b"\x64\0\0\0\0x14"
|
|
||||||
///
|
|
||||||
/// # Create structure object referring to address of
|
|
||||||
/// # the data in the buffer above
|
|
||||||
/// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf))
|
|
||||||
///
|
|
||||||
/// # Access fields
|
|
||||||
/// print(s.a, s.b)
|
|
||||||
/// # Result:
|
|
||||||
/// # 100, 20
|
|
||||||
|
|
||||||
#define LAYOUT_LITTLE_ENDIAN (0)
|
#define LAYOUT_LITTLE_ENDIAN (0)
|
||||||
#define LAYOUT_BIG_ENDIAN (1)
|
#define LAYOUT_BIG_ENDIAN (1)
|
||||||
@ -75,6 +47,7 @@
|
|||||||
#define BITF_LEN_BITS 5
|
#define BITF_LEN_BITS 5
|
||||||
#define BITF_OFF_BITS 5
|
#define BITF_OFF_BITS 5
|
||||||
#define OFFSET_BITS 17
|
#define OFFSET_BITS 17
|
||||||
|
#define LEN_BITS (OFFSET_BITS + BITF_OFF_BITS)
|
||||||
#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
|
#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
|
||||||
#error Invalid encoding field length
|
#error Invalid encoding field length
|
||||||
#endif
|
#endif
|
||||||
@ -191,7 +164,7 @@ STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_
|
|||||||
mp_uint_t item_s;
|
mp_uint_t item_s;
|
||||||
if (t->len == 2) {
|
if (t->len == 2) {
|
||||||
// Elements of array are scalar
|
// Elements of array are scalar
|
||||||
item_s = GET_SCALAR_SIZE(val_type);
|
item_s = uctypes_struct_scalar_size(val_type);
|
||||||
if (item_s > *max_field_size) {
|
if (item_s > *max_field_size) {
|
||||||
*max_field_size = item_s;
|
*max_field_size = item_s;
|
||||||
}
|
}
|
||||||
@ -419,10 +392,8 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
|||||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
|
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
|
||||||
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
||||||
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
||||||
// printf("scalar type=%d offset=%x\n", val_type, offset);
|
|
||||||
|
|
||||||
if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) {
|
if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) {
|
||||||
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
|
|
||||||
if (self->flags == LAYOUT_NATIVE) {
|
if (self->flags == LAYOUT_NATIVE) {
|
||||||
if (set_val == MP_OBJ_NULL) {
|
if (set_val == MP_OBJ_NULL) {
|
||||||
return get_aligned(val_type, self->addr + offset, 0);
|
return get_aligned(val_type, self->addr + offset, 0);
|
||||||
@ -439,9 +410,9 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (val_type >= BFUINT8 && val_type <= BFINT32) {
|
} else if (val_type >= BFUINT8 && val_type <= BFINT32) {
|
||||||
uint bit_offset = (offset >> 17) & 31;
|
uint bit_offset = (offset >> OFFSET_BITS) & 31;
|
||||||
uint bit_len = (offset >> 22) & 31;
|
uint bit_len = (offset >> LEN_BITS) & 31;
|
||||||
offset &= (1 << 17) - 1;
|
offset &= (1 << OFFSET_BITS) - 1;
|
||||||
mp_uint_t val;
|
mp_uint_t val;
|
||||||
if (self->flags == LAYOUT_NATIVE) {
|
if (self->flags == LAYOUT_NATIVE) {
|
||||||
val = get_aligned_basic(val_type & 6, self->addr + offset);
|
val = get_aligned_basic(val_type & 6, self->addr + offset);
|
||||||
@ -489,7 +460,6 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
|||||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
|
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
|
||||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||||
// printf("agg type=%d offset=%x\n", agg_type, offset);
|
|
||||||
|
|
||||||
switch (agg_type) {
|
switch (agg_type) {
|
||||||
case STRUCT: {
|
case STRUCT: {
|
||||||
@ -514,7 +484,6 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
|||||||
o->desc = MP_OBJ_FROM_PTR(sub);
|
o->desc = MP_OBJ_FROM_PTR(sub);
|
||||||
o->addr = self->addr + offset;
|
o->addr = self->addr + offset;
|
||||||
o->flags = self->flags;
|
o->flags = self->flags;
|
||||||
// printf("PTR/ARR base addr=%p\n", o->addr);
|
|
||||||
return MP_OBJ_FROM_PTR(o);
|
return MP_OBJ_FROM_PTR(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -572,7 +541,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob
|
|||||||
return value; // just !MP_OBJ_NULL
|
return value; // just !MP_OBJ_NULL
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index;
|
byte *p = self->addr + uctypes_struct_scalar_size(val_type) * index;
|
||||||
if (value == MP_OBJ_SENTINEL) {
|
if (value == MP_OBJ_SENTINEL) {
|
||||||
return get_unaligned(val_type, p, self->flags);
|
return get_unaligned(val_type, p, self->flags);
|
||||||
} else {
|
} else {
|
||||||
@ -647,9 +616,8 @@ STATIC mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \function addressof()
|
// addressof()
|
||||||
/// Return address of object's data (applies to object providing buffer
|
// Return address of object's data (applies to objects providing the buffer interface).
|
||||||
/// interface).
|
|
||||||
STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||||
@ -657,25 +625,20 @@ STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
|||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
|
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
|
||||||
|
|
||||||
/// \function bytearray_at()
|
// bytearray_at()
|
||||||
/// Capture memory at given address of given size as bytearray. Memory is
|
// Capture memory at given address of given size as bytearray.
|
||||||
/// captured by reference (and thus memory pointed by bytearray may change
|
|
||||||
/// or become invalid at later time). Use bytes_at() to capture by value.
|
|
||||||
STATIC mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
|
STATIC mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
|
||||||
return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr));
|
return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr));
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
|
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
|
||||||
|
|
||||||
/// \function bytes_at()
|
// bytes_at()
|
||||||
/// Capture memory at given address of given size as bytes. Memory is
|
// Capture memory at given address of given size as bytes.
|
||||||
/// captured by value, i.e. copied. Use bytearray_at() to capture by reference
|
|
||||||
/// ("zero copy").
|
|
||||||
STATIC mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
|
STATIC mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
|
||||||
return mp_obj_new_bytes((void *)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size));
|
return mp_obj_new_bytes((void *)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size));
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
|
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
|
||||||
|
|
||||||
|
|
||||||
STATIC const mp_obj_type_t uctypes_struct_type = {
|
STATIC const mp_obj_type_t uctypes_struct_type = {
|
||||||
{ &mp_type_type },
|
{ &mp_type_type },
|
||||||
.name = MP_QSTR_struct,
|
.name = MP_QSTR_struct,
|
||||||
@ -695,81 +658,63 @@ STATIC const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = {
|
|||||||
{ MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) },
|
||||||
|
|
||||||
/// \moduleref uctypes
|
|
||||||
|
|
||||||
/// \constant NATIVE - Native structure layout - native endianness,
|
|
||||||
/// platform-specific field alignment
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) },
|
{ MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) },
|
||||||
/// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed
|
|
||||||
/// (no alignment constraints)
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) },
|
{ MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) },
|
||||||
/// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed
|
|
||||||
/// (no alignment constraints)
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) },
|
{ MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) },
|
||||||
|
|
||||||
/// \constant VOID - void value type, may be used only as pointer target type.
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
{ MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||||
|
|
||||||
/// \constant UINT8 - uint8_t value type
|
{ MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, VAL_TYPE_BITS)) },
|
||||||
/// \constant INT8 - int8_t value type
|
{ MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
|
||||||
/// \constant UINT16 - uint16_t value type
|
{ MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||||
/// \constant INT16 - int16_t value type
|
{ MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||||
/// \constant UINT32 - uint32_t value type
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
|
|
||||||
/// \constant INT32 - int32_t value type
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
|
||||||
/// \constant UINT64 - uint64_t value type
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
|
|
||||||
/// \constant INT64 - int64_t value type
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, VAL_TYPE_BITS)) },
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(17) },
|
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(OFFSET_BITS) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(22) },
|
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(LEN_BITS) },
|
||||||
|
|
||||||
#if MICROPY_PY_BUILTINS_FLOAT
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, VAL_TYPE_BITS)) },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MICROPY_PY_UCTYPES_NATIVE_C_TYPES
|
#if MICROPY_PY_UCTYPES_NATIVE_C_TYPES
|
||||||
// C native type aliases. These depend on GCC-compatible predefined
|
// C native type aliases. These depend on GCC-compatible predefined
|
||||||
// preprocessor macros.
|
// preprocessor macros.
|
||||||
#if __SIZEOF_SHORT__ == 2
|
#if __SIZEOF_SHORT__ == 2
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
|
||||||
#endif
|
#endif
|
||||||
#if __SIZEOF_INT__ == 4
|
#if __SIZEOF_INT__ == 4
|
||||||
{ MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||||
#endif
|
#endif
|
||||||
#if __SIZEOF_LONG__ == 4
|
#if __SIZEOF_LONG__ == 4
|
||||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||||
#elif __SIZEOF_LONG__ == 8
|
#elif __SIZEOF_LONG__ == 8
|
||||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||||
#endif
|
#endif
|
||||||
#if __SIZEOF_LONG_LONG__ == 8
|
#if __SIZEOF_LONG_LONG__ == 8
|
||||||
{ MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
|
{ MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||||
#endif
|
#endif
|
||||||
#endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES
|
#endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
|
{ MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
|
{ MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table);
|
STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table);
|
||||||
|
|
||||||
const mp_obj_module_t mp_module_uctypes = {
|
const mp_obj_module_t mp_module_uctypes = {
|
||||||
|
|||||||
@ -60,9 +60,16 @@
|
|||||||
|
|
||||||
typedef struct _mp_obj_hash_t {
|
typedef struct _mp_obj_hash_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
char state[0];
|
bool final; // if set, update and digest raise an exception
|
||||||
|
uintptr_t state[0]; // must be aligned to a machine word
|
||||||
} mp_obj_hash_t;
|
} mp_obj_hash_t;
|
||||||
|
|
||||||
|
static void uhashlib_ensure_not_final(mp_obj_hash_t *self) {
|
||||||
|
if (self->final) {
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("hash is final"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if MICROPY_PY_UHASHLIB_SHA256
|
#if MICROPY_PY_UHASHLIB_SHA256
|
||||||
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
|
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
|
||||||
|
|
||||||
@ -78,6 +85,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context));
|
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context));
|
||||||
o->base.type = type;
|
o->base.type = type;
|
||||||
|
o->final = false;
|
||||||
mbedtls_sha256_init((mbedtls_sha256_context *)&o->state);
|
mbedtls_sha256_init((mbedtls_sha256_context *)&o->state);
|
||||||
mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0);
|
mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0);
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
@ -88,6 +96,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||||
mbedtls_sha256_update_ret((mbedtls_sha256_context *)&self->state, bufinfo.buf, bufinfo.len);
|
mbedtls_sha256_update_ret((mbedtls_sha256_context *)&self->state, bufinfo.buf, bufinfo.len);
|
||||||
@ -96,6 +105,8 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
|
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
|
self->final = true;
|
||||||
vstr_t vstr;
|
vstr_t vstr;
|
||||||
vstr_init_len(&vstr, 32);
|
vstr_init_len(&vstr, 32);
|
||||||
mbedtls_sha256_finish_ret((mbedtls_sha256_context *)&self->state, (unsigned char *)vstr.buf);
|
mbedtls_sha256_finish_ret((mbedtls_sha256_context *)&self->state, (unsigned char *)vstr.buf);
|
||||||
@ -110,6 +121,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));
|
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));
|
||||||
o->base.type = type;
|
o->base.type = type;
|
||||||
|
o->final = false;
|
||||||
sha256_init((CRYAL_SHA256_CTX *)o->state);
|
sha256_init((CRYAL_SHA256_CTX *)o->state);
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
|
uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||||
@ -119,6 +131,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||||
sha256_update((CRYAL_SHA256_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
sha256_update((CRYAL_SHA256_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||||
@ -127,6 +140,8 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
|
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
|
self->final = true;
|
||||||
vstr_t vstr;
|
vstr_t vstr;
|
||||||
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
|
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
|
||||||
sha256_final((CRYAL_SHA256_CTX *)self->state, (byte *)vstr.buf);
|
sha256_final((CRYAL_SHA256_CTX *)self->state, (byte *)vstr.buf);
|
||||||
@ -160,6 +175,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
|
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
|
||||||
o->base.type = type;
|
o->base.type = type;
|
||||||
|
o->final = false;
|
||||||
SHA1_Init((SHA1_CTX *)o->state);
|
SHA1_Init((SHA1_CTX *)o->state);
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
|
uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||||
@ -169,6 +185,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||||
SHA1_Update((SHA1_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
SHA1_Update((SHA1_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||||
@ -177,6 +194,8 @@ STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
|
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
|
self->final = true;
|
||||||
vstr_t vstr;
|
vstr_t vstr;
|
||||||
vstr_init_len(&vstr, SHA1_SIZE);
|
vstr_init_len(&vstr, SHA1_SIZE);
|
||||||
SHA1_Final((byte *)vstr.buf, (SHA1_CTX *)self->state);
|
SHA1_Final((byte *)vstr.buf, (SHA1_CTX *)self->state);
|
||||||
@ -196,6 +215,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context));
|
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context));
|
||||||
o->base.type = type;
|
o->base.type = type;
|
||||||
|
o->final = false;
|
||||||
mbedtls_sha1_init((mbedtls_sha1_context *)o->state);
|
mbedtls_sha1_init((mbedtls_sha1_context *)o->state);
|
||||||
mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state);
|
mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state);
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
@ -206,6 +226,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||||
mbedtls_sha1_update_ret((mbedtls_sha1_context *)self->state, bufinfo.buf, bufinfo.len);
|
mbedtls_sha1_update_ret((mbedtls_sha1_context *)self->state, bufinfo.buf, bufinfo.len);
|
||||||
@ -214,6 +235,8 @@ STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
|
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
|
self->final = true;
|
||||||
vstr_t vstr;
|
vstr_t vstr;
|
||||||
vstr_init_len(&vstr, 20);
|
vstr_init_len(&vstr, 20);
|
||||||
mbedtls_sha1_finish_ret((mbedtls_sha1_context *)self->state, (byte *)vstr.buf);
|
mbedtls_sha1_finish_ret((mbedtls_sha1_context *)self->state, (byte *)vstr.buf);
|
||||||
@ -247,6 +270,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(MD5_CTX));
|
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(MD5_CTX));
|
||||||
o->base.type = type;
|
o->base.type = type;
|
||||||
|
o->final = false;
|
||||||
MD5_Init((MD5_CTX *)o->state);
|
MD5_Init((MD5_CTX *)o->state);
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
|
uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||||
@ -256,6 +280,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||||
MD5_Update((MD5_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
MD5_Update((MD5_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||||
@ -264,6 +289,8 @@ STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
|
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
|
self->final = true;
|
||||||
vstr_t vstr;
|
vstr_t vstr;
|
||||||
vstr_init_len(&vstr, MD5_SIZE);
|
vstr_init_len(&vstr, MD5_SIZE);
|
||||||
MD5_Final((byte *)vstr.buf, (MD5_CTX *)self->state);
|
MD5_Final((byte *)vstr.buf, (MD5_CTX *)self->state);
|
||||||
@ -283,6 +310,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context));
|
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context));
|
||||||
o->base.type = type;
|
o->base.type = type;
|
||||||
|
o->final = false;
|
||||||
mbedtls_md5_init((mbedtls_md5_context *)o->state);
|
mbedtls_md5_init((mbedtls_md5_context *)o->state);
|
||||||
mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state);
|
mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state);
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
@ -293,6 +321,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||||
mbedtls_md5_update_ret((mbedtls_md5_context *)self->state, bufinfo.buf, bufinfo.len);
|
mbedtls_md5_update_ret((mbedtls_md5_context *)self->state, bufinfo.buf, bufinfo.len);
|
||||||
@ -301,6 +330,8 @@ STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||||||
|
|
||||||
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
|
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
|
||||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
uhashlib_ensure_not_final(self);
|
||||||
|
self->final = true;
|
||||||
vstr_t vstr;
|
vstr_t vstr;
|
||||||
vstr_init_len(&vstr, 16);
|
vstr_init_len(&vstr, 16);
|
||||||
mbedtls_md5_finish_ret((mbedtls_md5_context *)self->state, (byte *)vstr.buf);
|
mbedtls_md5_finish_ret((mbedtls_md5_context *)self->state, (byte *)vstr.buf);
|
||||||
|
|||||||
@ -87,8 +87,11 @@ STATIC uint32_t yasmarang_randbelow(uint32_t n) {
|
|||||||
|
|
||||||
STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {
|
STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {
|
||||||
int n = mp_obj_get_int(num_in);
|
int n = mp_obj_get_int(num_in);
|
||||||
if (n > 32 || n == 0) {
|
if (n > 32 || n < 0) {
|
||||||
mp_raise_ValueError(NULL);
|
mp_raise_ValueError(MP_ERROR_TEXT("bits must be 32 or less"));
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
return MP_OBJ_NEW_SMALL_INT(0);
|
||||||
}
|
}
|
||||||
uint32_t mask = ~0;
|
uint32_t mask = ~0;
|
||||||
// Beware of C undefined behavior when shifting by >= than bit size
|
// Beware of C undefined behavior when shifting by >= than bit size
|
||||||
|
|||||||
@ -40,10 +40,6 @@
|
|||||||
// Flags for poll()
|
// Flags for poll()
|
||||||
#define FLAG_ONESHOT (1)
|
#define FLAG_ONESHOT (1)
|
||||||
|
|
||||||
/// \module select - Provides select function to wait for events on a stream
|
|
||||||
///
|
|
||||||
/// This module provides the select function.
|
|
||||||
|
|
||||||
typedef struct _poll_obj_t {
|
typedef struct _poll_obj_t {
|
||||||
mp_obj_t obj;
|
mp_obj_t obj;
|
||||||
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
|
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
|
||||||
@ -111,7 +107,7 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
|
|||||||
return n_ready;
|
return n_ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \function select(rlist, wlist, xlist[, timeout])
|
// select(rlist, wlist, xlist[, timeout])
|
||||||
STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
||||||
// get array data from tuple/list arguments
|
// get array data from tuple/list arguments
|
||||||
size_t rwx_len[3];
|
size_t rwx_len[3];
|
||||||
@ -178,8 +174,6 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
|||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
|
||||||
|
|
||||||
/// \class Poll - poll class
|
|
||||||
|
|
||||||
typedef struct _mp_obj_poll_t {
|
typedef struct _mp_obj_poll_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_map_t poll_map;
|
mp_map_t poll_map;
|
||||||
@ -190,7 +184,7 @@ typedef struct _mp_obj_poll_t {
|
|||||||
mp_obj_t ret_tuple;
|
mp_obj_t ret_tuple;
|
||||||
} mp_obj_poll_t;
|
} mp_obj_poll_t;
|
||||||
|
|
||||||
/// \method register(obj[, eventmask])
|
// register(obj[, eventmask])
|
||||||
STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
|
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
mp_uint_t flags;
|
mp_uint_t flags;
|
||||||
@ -204,7 +198,7 @@ STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
|
|||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
|
||||||
|
|
||||||
/// \method unregister(obj)
|
// unregister(obj)
|
||||||
STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
|
STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
|
||||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
|
mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
|
||||||
@ -213,7 +207,7 @@ STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
|
|||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
|
MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
|
||||||
|
|
||||||
/// \method modify(obj, eventmask)
|
// modify(obj, eventmask)
|
||||||
STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
|
STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
|
||||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
|
mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
|
||||||
@ -348,7 +342,7 @@ STATIC const mp_obj_type_t mp_type_poll = {
|
|||||||
.locals_dict = (void *)&poll_locals_dict,
|
.locals_dict = (void *)&poll_locals_dict,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \function poll()
|
// poll()
|
||||||
STATIC mp_obj_t select_poll(void) {
|
STATIC mp_obj_t select_poll(void) {
|
||||||
mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t);
|
mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t);
|
||||||
poll->base.type = &mp_type_poll;
|
poll->base.type = &mp_type_poll;
|
||||||
|
|||||||
@ -82,7 +82,7 @@ async def open_connection(host, port):
|
|||||||
try:
|
try:
|
||||||
s.connect(ai[-1])
|
s.connect(ai[-1])
|
||||||
except OSError as er:
|
except OSError as er:
|
||||||
if er.args[0] != EINPROGRESS:
|
if er.errno != EINPROGRESS:
|
||||||
raise er
|
raise er
|
||||||
yield core._io_queue.queue_write(s)
|
yield core._io_queue.queue_write(s)
|
||||||
return ss, ss
|
return ss, ss
|
||||||
@ -112,7 +112,6 @@ class Server:
|
|||||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
s.bind(ai[-1])
|
s.bind(ai[-1])
|
||||||
s.listen(backlog)
|
s.listen(backlog)
|
||||||
self.task = core.cur_task
|
|
||||||
# Accept incoming connections
|
# Accept incoming connections
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -135,7 +134,7 @@ class Server:
|
|||||||
# TODO could use an accept-callback on socket read activity instead of creating a task
|
# TODO could use an accept-callback on socket read activity instead of creating a task
|
||||||
async def start_server(cb, host, port, backlog=5):
|
async def start_server(cb, host, port, backlog=5):
|
||||||
s = Server()
|
s = Server()
|
||||||
core.create_task(s._serve(cb, host, port, backlog))
|
s.task = core.create_task(s._serve(cb, host, port, backlog))
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -133,7 +133,7 @@ int mp_uos_dupterm_rx_chr(void) {
|
|||||||
nlr_pop();
|
nlr_pop();
|
||||||
if (buf[0] == mp_interrupt_char) {
|
if (buf[0] == mp_interrupt_char) {
|
||||||
// Signal keyboard interrupt to be raised as soon as the VM resumes
|
// Signal keyboard interrupt to be raised as soon as the VM resumes
|
||||||
mp_keyboard_interrupt();
|
mp_sched_keyboard_interrupt();
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
return buf[0];
|
return buf[0];
|
||||||
|
|||||||
@ -256,7 +256,7 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) {
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir);
|
||||||
|
|
||||||
/// Change current directory.
|
// Change current directory.
|
||||||
STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
|
STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||||
const char *path;
|
const char *path;
|
||||||
@ -272,7 +272,7 @@ STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir);
|
||||||
|
|
||||||
/// Get the current directory.
|
// Get the current directory.
|
||||||
STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
|
STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
|
||||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||||
char buf[MICROPY_ALLOC_PATH_MAX + 1];
|
char buf[MICROPY_ALLOC_PATH_MAX + 1];
|
||||||
@ -284,8 +284,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd);
|
||||||
|
|
||||||
/// \function stat(path)
|
// Get the status of a file or directory.
|
||||||
/// Get the status of a file or directory.
|
|
||||||
STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
|
STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||||
const char *path = mp_obj_str_get_str(path_in);
|
const char *path = mp_obj_str_get_str(path_in);
|
||||||
|
|||||||
@ -588,8 +588,8 @@ friendly_repl_reset:
|
|||||||
|
|
||||||
// If the GC is locked at this point there is no way out except a reset,
|
// If the GC is locked at this point there is no way out except a reset,
|
||||||
// so force the GC to be unlocked to help the user debug what went wrong.
|
// so force the GC to be unlocked to help the user debug what went wrong.
|
||||||
if (MP_STATE_MEM(gc_lock_depth) != 0) {
|
if (MP_STATE_THREAD(gc_lock_depth) != 0) {
|
||||||
MP_STATE_MEM(gc_lock_depth) = 0;
|
MP_STATE_THREAD(gc_lock_depth) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vstr_reset(&line);
|
vstr_reset(&line);
|
||||||
|
|||||||
@ -41,7 +41,6 @@ extern pyexec_mode_kind_t pyexec_mode_kind;
|
|||||||
extern int pyexec_system_exit;
|
extern int pyexec_system_exit;
|
||||||
|
|
||||||
#define PYEXEC_FORCED_EXIT (0x100)
|
#define PYEXEC_FORCED_EXIT (0x100)
|
||||||
#define PYEXEC_SWITCH_MODE (0x200)
|
|
||||||
|
|
||||||
int pyexec_raw_repl(void);
|
int pyexec_raw_repl(void);
|
||||||
int pyexec_friendly_repl(void);
|
int pyexec_friendly_repl(void);
|
||||||
|
|||||||
132
lib/utils/semihosting.c
Normal file
132
lib/utils/semihosting.c
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Ayke van Laethem
|
||||||
|
*
|
||||||
|
* 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 "semihosting.h"
|
||||||
|
|
||||||
|
// Resources:
|
||||||
|
// http://embed.rs/articles/2016/semi-hosting-rust/
|
||||||
|
// https://wiki.dlang.org/Minimal_semihosted_ARM_Cortex-M_%22Hello_World%22
|
||||||
|
// https://github.com/arduino/OpenOCD/blob/master/src/target/arm_semihosting.c
|
||||||
|
|
||||||
|
#define SYS_OPEN 0x01
|
||||||
|
#define SYS_WRITEC 0x03
|
||||||
|
#define SYS_WRITE 0x05
|
||||||
|
#define SYS_READC 0x07
|
||||||
|
|
||||||
|
// Constants:
|
||||||
|
#define OPEN_MODE_READ (0) // mode "r"
|
||||||
|
#define OPEN_MODE_WRITE (4) // mode "w"
|
||||||
|
|
||||||
|
#ifndef __thumb__
|
||||||
|
#error Semihosting is only implemented for ARM microcontrollers.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int mp_semihosting_stdout;
|
||||||
|
|
||||||
|
static uint32_t mp_semihosting_call(uint32_t num, const void *arg) {
|
||||||
|
// A semihosting call works as follows, similar to a SVCall:
|
||||||
|
// * the call is invoked by a special breakpoint: 0xAB
|
||||||
|
// * the command is placed in r0
|
||||||
|
// * a pointer to the arguments is placed in r1
|
||||||
|
// * the return value is placed in r0
|
||||||
|
// Note that because it uses the breakpoint instruction, applications
|
||||||
|
// will hang if they're not connected to a debugger. And they'll be
|
||||||
|
// stuck in a breakpoint if semihosting is not specifically enabled in
|
||||||
|
// the debugger.
|
||||||
|
// Also note that semihosting is extremely slow (sometimes >100ms per
|
||||||
|
// call).
|
||||||
|
register uint32_t num_reg __asm__ ("r0") = num;
|
||||||
|
register const void *args_reg __asm__ ("r1") = arg;
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"bkpt 0xAB\n" // invoke semihosting call
|
||||||
|
: "+r" (num_reg) // call number and result
|
||||||
|
: "r" (args_reg) // arguments
|
||||||
|
: "memory"); // make sure args aren't optimized away
|
||||||
|
return num_reg; // r0, which became the result
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mp_semihosting_open_console(uint32_t mode) {
|
||||||
|
struct {
|
||||||
|
char *name;
|
||||||
|
uint32_t mode;
|
||||||
|
uint32_t name_len;
|
||||||
|
} args = {
|
||||||
|
.name = ":tt", // magic path to console
|
||||||
|
.mode = mode, // e.g. "r", "w" (see OPEN_MODE_* constants)
|
||||||
|
.name_len = 3, // strlen(":tt")
|
||||||
|
};
|
||||||
|
return mp_semihosting_call(SYS_OPEN, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mp_semihosting_init() {
|
||||||
|
mp_semihosting_stdout = mp_semihosting_open_console(OPEN_MODE_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mp_semihosting_rx_char() {
|
||||||
|
return mp_semihosting_call(SYS_READC, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_semihosting_tx_char(char c) {
|
||||||
|
mp_semihosting_call(SYS_WRITEC, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mp_semihosting_tx_strn(const char *str, size_t len) {
|
||||||
|
if (len == 0) {
|
||||||
|
return 0; // nothing to do
|
||||||
|
}
|
||||||
|
if (len == 1) {
|
||||||
|
mp_semihosting_tx_char(*str); // maybe faster?
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t fd;
|
||||||
|
const char *str;
|
||||||
|
uint32_t len;
|
||||||
|
} args = {
|
||||||
|
.fd = mp_semihosting_stdout,
|
||||||
|
.str = str,
|
||||||
|
.len = len,
|
||||||
|
};
|
||||||
|
return mp_semihosting_call(SYS_WRITE, &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mp_semihosting_tx_strn_cooked(const char *str, size_t len) {
|
||||||
|
// Write chunks of data until (excluding) the first '\n' character,
|
||||||
|
// insert a '\r' character, and then continue with the next chunk
|
||||||
|
// (starting with '\n').
|
||||||
|
// Doing byte-by-byte writes would be easier to implement but is far
|
||||||
|
// too slow.
|
||||||
|
size_t start = 0;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
if (str[i] == '\n') {
|
||||||
|
mp_semihosting_tx_strn(str + start, i - start);
|
||||||
|
mp_semihosting_tx_char('\r');
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mp_semihosting_tx_strn(str + start, len - start);
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2020 Philipp Ebensberger
|
* Copyright (c) 2018 Ayke van Laethem
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -23,11 +23,29 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef MICROPY_INCLUDED_LIB_UTILS_SEMIHOSTING_H
|
||||||
|
#define MICROPY_INCLUDED_LIB_UTILS_SEMIHOSTING_H
|
||||||
|
|
||||||
#include "pin.h"
|
/*
|
||||||
|
|
||||||
static pin_af_obj_t GPIO_11_af[] = {
|
To use semi-hosting for a replacement UART:
|
||||||
PIN_AF(GPIOMUX_IO11, PIN_AF_MODE_ALT5, GPIO1, 0x10B0U),
|
- Add lib/semihosting/semihosting.c to the Makefile sources.
|
||||||
};
|
- Call mp_semihosting_init() in main(), around the time UART is initialized.
|
||||||
|
- Replace mp_hal_stdin_rx_chr and similar in mphalport.c with the semihosting equivalent.
|
||||||
|
- Include lib/semihosting/semihosting.h in the relevant files.
|
||||||
|
|
||||||
pin_obj_t GPIO_11 = PIN(GPIO_11, GPIO1, 5, GPIO_11_af);
|
Then make sure the debugger is attached and enables semihosting. In OpenOCD this is
|
||||||
|
done with ARM semihosting enable followed by reset. The terminal will need further
|
||||||
|
configuration to work with MicroPython (bash: stty raw -echo).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void mp_semihosting_init();
|
||||||
|
int mp_semihosting_rx_char();
|
||||||
|
uint32_t mp_semihosting_tx_strn(const char *str, size_t len);
|
||||||
|
uint32_t mp_semihosting_tx_strn_cooked(const char *str, size_t len);
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_LIB_UTILS_SEMIHOSTING_H
|
||||||
@ -5,7 +5,7 @@ include ../../py/mkenv.mk
|
|||||||
include $(TOP)/py/py.mk
|
include $(TOP)/py/py.mk
|
||||||
|
|
||||||
# Set makefile-level MicroPython feature configurations.
|
# Set makefile-level MicroPython feature configurations.
|
||||||
MICROPY_ROM_TEXT_COMPRESSION ?= 1
|
MICROPY_ROM_TEXT_COMPRESSION ?= 0
|
||||||
|
|
||||||
# Define toolchain and other tools.
|
# Define toolchain and other tools.
|
||||||
CROSS_COMPILE ?= arm-none-eabi-
|
CROSS_COMPILE ?= arm-none-eabi-
|
||||||
|
|||||||
@ -18,4 +18,4 @@ compiled and executed when the firmware starts. They produce output on the
|
|||||||
system's stdout.
|
system's stdout.
|
||||||
|
|
||||||
The size of the firmware (the machine code that is programmed to the
|
The size of the firmware (the machine code that is programmed to the
|
||||||
microcontroller's flash/ROM) is currently around 61200 bytes.
|
microcontroller's flash/ROM) is currently around 57900 bytes.
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
// Python internal features
|
// Python internal features
|
||||||
#define MICROPY_ENABLE_EXTERNAL_IMPORT (0)
|
#define MICROPY_ENABLE_EXTERNAL_IMPORT (0)
|
||||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NONE)
|
||||||
#define MICROPY_CPYTHON_COMPAT (0)
|
#define MICROPY_CPYTHON_COMPAT (0)
|
||||||
#define MICROPY_MODULE_GETATTR (0)
|
#define MICROPY_MODULE_GETATTR (0)
|
||||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
|
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
|
||||||
|
|||||||
@ -250,7 +250,7 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
|||||||
int data = MAP_UARTCharGetNonBlocking(self->reg);
|
int data = MAP_UARTCharGetNonBlocking(self->reg);
|
||||||
if (MP_STATE_PORT(os_term_dup_obj) && MP_STATE_PORT(os_term_dup_obj)->stream_o == self && data == mp_interrupt_char) {
|
if (MP_STATE_PORT(os_term_dup_obj) && MP_STATE_PORT(os_term_dup_obj)->stream_o == self && data == mp_interrupt_char) {
|
||||||
// raise an exception when interrupts are finished
|
// raise an exception when interrupts are finished
|
||||||
mp_keyboard_interrupt();
|
mp_sched_keyboard_interrupt();
|
||||||
} else { // there's always a read buffer available
|
} else { // there's always a read buffer available
|
||||||
uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN;
|
uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN;
|
||||||
if (next_head != self->read_buf_tail) {
|
if (next_head != self->read_buf_tail) {
|
||||||
|
|||||||
@ -446,7 +446,7 @@ static void telnet_parse_input (uint8_t *str, int16_t *len) {
|
|||||||
if (*_str <= 127) {
|
if (*_str <= 127) {
|
||||||
if (telnet_data.state == E_TELNET_STE_LOGGED_IN && *_str == mp_interrupt_char) {
|
if (telnet_data.state == E_TELNET_STE_LOGGED_IN && *_str == mp_interrupt_char) {
|
||||||
// raise a keyboard exception
|
// raise a keyboard exception
|
||||||
mp_keyboard_interrupt();
|
mp_sched_keyboard_interrupt();
|
||||||
(*len)--;
|
(*len)--;
|
||||||
_str++;
|
_str++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Top-level cmake file for building MicroPython on ESP32.
|
# Top-level cmake file for building MicroPython on ESP32.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.18)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
# Set the location of this port's directory.
|
# Set the location of this port's directory.
|
||||||
set(MICROPY_PORT_DIR ${CMAKE_SOURCE_DIR})
|
set(MICROPY_PORT_DIR ${CMAKE_SOURCE_DIR})
|
||||||
|
|||||||
@ -26,6 +26,10 @@ endif
|
|||||||
|
|
||||||
IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -B $(BUILD) $(CMAKE_ARGS)
|
IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -B $(BUILD) $(CMAKE_ARGS)
|
||||||
|
|
||||||
|
ifdef FROZEN_MANIFEST
|
||||||
|
IDFPY_FLAGS += -D MICROPY_FROZEN_MANIFEST=$(FROZEN_MANIFEST)
|
||||||
|
endif
|
||||||
|
|
||||||
all:
|
all:
|
||||||
idf.py $(IDFPY_FLAGS) build
|
idf.py $(IDFPY_FLAGS) build
|
||||||
@$(PYTHON) makeimg.py \
|
@$(PYTHON) makeimg.py \
|
||||||
@ -34,7 +38,7 @@ all:
|
|||||||
$(BUILD)/micropython.bin \
|
$(BUILD)/micropython.bin \
|
||||||
$(BUILD)/firmware.bin
|
$(BUILD)/firmware.bin
|
||||||
|
|
||||||
$(BUILD)/bootloader/bootloader.bin $(BUILD)/partition_table/partition -table.bin $(BUILD)/micropython.bin: FORCE
|
$(BUILD)/bootloader/bootloader.bin $(BUILD)/partition_table/partition-table.bin $(BUILD)/micropython.bin: FORCE
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
idf.py $(IDFPY_FLAGS) fullclean
|
idf.py $(IDFPY_FLAGS) fullclean
|
||||||
|
|||||||
@ -2,5 +2,6 @@ set(SDKCONFIG_DEFAULTS
|
|||||||
boards/sdkconfig.base
|
boards/sdkconfig.base
|
||||||
boards/sdkconfig.ble
|
boards/sdkconfig.ble
|
||||||
)
|
)
|
||||||
|
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
||||||
|
endif()
|
||||||
|
|||||||
@ -4,4 +4,6 @@ set(SDKCONFIG_DEFAULTS
|
|||||||
boards/GENERIC_D2WD/sdkconfig.board
|
boards/GENERIC_D2WD/sdkconfig.board
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||||
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
||||||
|
endif()
|
||||||
|
|||||||
@ -4,4 +4,6 @@ set(SDKCONFIG_DEFAULTS
|
|||||||
boards/GENERIC_OTA/sdkconfig.board
|
boards/GENERIC_OTA/sdkconfig.board
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||||
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
||||||
|
endif()
|
||||||
|
|||||||
@ -5,4 +5,6 @@ set(SDKCONFIG_DEFAULTS
|
|||||||
boards/sdkconfig.usb
|
boards/sdkconfig.usb
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||||
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
||||||
|
endif()
|
||||||
|
|||||||
@ -5,4 +5,6 @@ set(SDKCONFIG_DEFAULTS
|
|||||||
boards/sdkconfig.240mhz
|
boards/sdkconfig.240mhz
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||||
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
||||||
|
endif()
|
||||||
|
|||||||
75
ports/esp32/boards/M5STACK_ATOM/modules/atom.py
Normal file
75
ports/esp32/boards/M5STACK_ATOM/modules/atom.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# M5Stack ATOM MicroPython Helper Library
|
||||||
|
# MIT license; Copyright (c) 2021 IAMLIUBO work for M5STACK
|
||||||
|
#
|
||||||
|
# Hardware details:
|
||||||
|
# ATOM Lite https://docs.m5stack.com/en/core/atom_lite
|
||||||
|
# ATOM Matrix https://docs.m5stack.com/en/core/atom_matrix
|
||||||
|
|
||||||
|
from micropython import const
|
||||||
|
from machine import Pin
|
||||||
|
import neopixel
|
||||||
|
|
||||||
|
# M5STACK ATOM Hardware Pin Assignments
|
||||||
|
"""
|
||||||
|
FRONT
|
||||||
|
|3V3|
|
||||||
|
|G21| IR G12 |G22|
|
||||||
|
|G25| BTN G39 |G19|
|
||||||
|
| 5V| WS2812 G27 |G23|
|
||||||
|
|GNG| MPU G21 G25 |G33|
|
||||||
|
G32 G26 5V GND
|
||||||
|
Grove Port
|
||||||
|
"""
|
||||||
|
|
||||||
|
# WS2812
|
||||||
|
WS2812_PIN = const(27)
|
||||||
|
|
||||||
|
# Button
|
||||||
|
BUTTON_PIN = const(39)
|
||||||
|
|
||||||
|
# IR
|
||||||
|
IR_PIN = const(12)
|
||||||
|
|
||||||
|
# I2C
|
||||||
|
I2C0_SCL_PIN = const(21)
|
||||||
|
I2C0_SDA_PIN = const(25)
|
||||||
|
|
||||||
|
# Grove port
|
||||||
|
GROVE_PORT_PIN = (const(26), const(32))
|
||||||
|
|
||||||
|
|
||||||
|
class ATOM:
|
||||||
|
def __init__(self, np_n):
|
||||||
|
self._np = neopixel.NeoPixel(pin=Pin(WS2812_PIN), n=np_n)
|
||||||
|
self._btn = Pin(BUTTON_PIN, Pin.IN, Pin.PULL_UP)
|
||||||
|
|
||||||
|
def get_button_status(self):
|
||||||
|
return self._btn.value()
|
||||||
|
|
||||||
|
def set_button_callback(self, cb):
|
||||||
|
self._btn.irq(trigger=Pin.IRQ_FALLING, handler=cb)
|
||||||
|
|
||||||
|
def set_pixel_color(self, num, r, g, b):
|
||||||
|
if num <= self._np.n:
|
||||||
|
self._np[num] = [r, g, b]
|
||||||
|
self._np.write()
|
||||||
|
|
||||||
|
def get_pixel_color(self, num):
|
||||||
|
if num <= self._np.n:
|
||||||
|
return self._np[num]
|
||||||
|
|
||||||
|
def set_pixels_color(self, r, g, b):
|
||||||
|
self._np.fill([r, g, b])
|
||||||
|
self._np.write()
|
||||||
|
|
||||||
|
|
||||||
|
class Lite(ATOM):
|
||||||
|
# WS2812 number: 1
|
||||||
|
def __init__(self):
|
||||||
|
super(Lite, self).__init__(np_n=1)
|
||||||
|
|
||||||
|
|
||||||
|
class Matrix(ATOM):
|
||||||
|
# WS2812 number: 25
|
||||||
|
def __init__(self):
|
||||||
|
super(Matrix, self).__init__(np_n=25)
|
||||||
10
ports/esp32/boards/M5STACK_ATOM/mpconfigboard.cmake
Normal file
10
ports/esp32/boards/M5STACK_ATOM/mpconfigboard.cmake
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
boards/sdkconfig.base
|
||||||
|
boards/sdkconfig.ble
|
||||||
|
boards/sdkconfig.240mhz
|
||||||
|
boards/M5STACK_ATOM/sdkconfig.board
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||||
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
|
||||||
|
endif()
|
||||||
2
ports/esp32/boards/M5STACK_ATOM/mpconfigboard.h
Normal file
2
ports/esp32/boards/M5STACK_ATOM/mpconfigboard.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#define MICROPY_HW_BOARD_NAME "M5Stack ATOM"
|
||||||
|
#define MICROPY_HW_MCU_NAME "ESP32-PICO-D4"
|
||||||
5
ports/esp32/boards/M5STACK_ATOM/sdkconfig.board
Normal file
5
ports/esp32/boards/M5STACK_ATOM/sdkconfig.board
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
CONFIG_FLASHMODE_QIO=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||||
|
CONFIG_SPIRAM_SPEED_80M=y
|
||||||
|
CONFIG_ESP32_REV_MIN_1=y
|
||||||
|
CONFIG_LWIP_LOCAL_HOSTNAME="M5StackATOM"
|
||||||
@ -1,9 +0,0 @@
|
|||||||
set(SDKCONFIG_DEFAULTS
|
|
||||||
boards/sdkconfig.base
|
|
||||||
boards/sdkconfig.ble
|
|
||||||
boards/sdkconfig.240mhz
|
|
||||||
boards/sdkconfig.spiram
|
|
||||||
boards/TINYPICO/sdkconfig.board
|
|
||||||
)
|
|
||||||
|
|
||||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#define MICROPY_HW_BOARD_NAME "TinyPICO"
|
|
||||||
#define MICROPY_HW_MCU_NAME "ESP32-PICO-D4"
|
|
||||||
3
ports/esp32/boards/UM_FEATHERS2/manifest.py
Normal file
3
ports/esp32/boards/UM_FEATHERS2/manifest.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
include("$(PORT_DIR)/boards/manifest.py")
|
||||||
|
freeze("$(PORT_DIR)/boards/UM_TINYPICO/modules", "dotstar.py")
|
||||||
|
freeze("modules")
|
||||||
101
ports/esp32/boards/UM_FEATHERS2/modules/feathers2.py
Normal file
101
ports/esp32/boards/UM_FEATHERS2/modules/feathers2.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# FeatherS2 MicroPython Helper Library
|
||||||
|
# 2021 Seon Rozenblum - Unexpected Maker
|
||||||
|
#
|
||||||
|
# Project home:
|
||||||
|
# https://feathers2.io
|
||||||
|
#
|
||||||
|
# 2021-Mar-21 - v0.1 - Initial implementation
|
||||||
|
|
||||||
|
# Import required libraries
|
||||||
|
from micropython import const
|
||||||
|
from machine import Pin, SPI, ADC
|
||||||
|
import machine, time
|
||||||
|
|
||||||
|
# FeatherS2 Hardware Pin Assignments
|
||||||
|
|
||||||
|
# LDO
|
||||||
|
LDO2 = const(21)
|
||||||
|
|
||||||
|
# APA102 Dotstar pins
|
||||||
|
DOTSTAR_CLK = const(45)
|
||||||
|
DOTSTAR_DATA = const(40)
|
||||||
|
|
||||||
|
# SPI
|
||||||
|
SPI_MOSI = const(35)
|
||||||
|
SPI_MISO = const(37)
|
||||||
|
SPI_CLK = const(36)
|
||||||
|
|
||||||
|
# I2C
|
||||||
|
I2C_SDA = const(8)
|
||||||
|
I2C_SCL = const(9)
|
||||||
|
|
||||||
|
# DAC
|
||||||
|
DAC1 = const(17)
|
||||||
|
DAC2 = const(18)
|
||||||
|
|
||||||
|
# LED & Ambient Light Sensor
|
||||||
|
LED = const(13)
|
||||||
|
AMB_LIGHT = const(4)
|
||||||
|
|
||||||
|
# Helper functions
|
||||||
|
|
||||||
|
# LED & Ambient Light Sensor control
|
||||||
|
def set_led(state):
|
||||||
|
l = Pin(LED, Pin.OUT)
|
||||||
|
l.value(state)
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_led(state):
|
||||||
|
l = Pin(LED, Pin.OUT)
|
||||||
|
l.value(not l.value())
|
||||||
|
|
||||||
|
|
||||||
|
# Create ADC and set attenuation and return the ambient light value from the onboard sensor
|
||||||
|
def get_amb_light():
|
||||||
|
adc = ADC(Pin(AMB_LIGHT))
|
||||||
|
adc.atten(ADC.ATTN_11DB)
|
||||||
|
return adc.read()
|
||||||
|
|
||||||
|
|
||||||
|
# LDO2 power control
|
||||||
|
# When we manually turn off the second LDO we also set the DotStar DATA and CLK pins to input to
|
||||||
|
# prevent parasitic power from lighting the LED even with the LDO off, causing current use.
|
||||||
|
# The DotStar is a beautiful LED, but parasitic power makes it a terrible choice for battery use :(
|
||||||
|
def set_ldo2_power(state):
|
||||||
|
"""Set the power for the on-board Dotstar to allow no current draw when not needed."""
|
||||||
|
# Set the power pin to the inverse of state
|
||||||
|
ldo2 = Pin(LDO2, Pin.OUT)
|
||||||
|
ldo2.value(state)
|
||||||
|
|
||||||
|
if state:
|
||||||
|
Pin(DOTSTAR_CLK, Pin.OUT)
|
||||||
|
Pin(DOTSTAR_DATA, Pin.OUT) # If power is on, set CLK to be output, otherwise input
|
||||||
|
else:
|
||||||
|
Pin(DOTSTAR_CLK, Pin.IN)
|
||||||
|
Pin(DOTSTAR_DATA, Pin.IN) # If power is on, set CLK to be output, otherwise input
|
||||||
|
|
||||||
|
# A small delay to let the IO change state
|
||||||
|
time.sleep(0.035)
|
||||||
|
|
||||||
|
|
||||||
|
# Dotstar rainbow colour wheel
|
||||||
|
def dotstar_color_wheel(wheel_pos):
|
||||||
|
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
|
||||||
|
wheel_pos = wheel_pos % 255
|
||||||
|
|
||||||
|
if wheel_pos < 85:
|
||||||
|
return 255 - wheel_pos * 3, 0, wheel_pos * 3
|
||||||
|
elif wheel_pos < 170:
|
||||||
|
wheel_pos -= 85
|
||||||
|
return 0, wheel_pos * 3, 255 - wheel_pos * 3
|
||||||
|
else:
|
||||||
|
wheel_pos -= 170
|
||||||
|
return wheel_pos * 3, 255 - wheel_pos * 3, 0
|
||||||
|
|
||||||
|
|
||||||
|
# Go into deep sleep but shut down the APA first to save power
|
||||||
|
# Use this if you want lowest deep sleep current
|
||||||
|
def go_deepsleep(t):
|
||||||
|
"""Deep sleep helper that also powers down the on-board Dotstar."""
|
||||||
|
set_ldo2_power(False)
|
||||||
|
machine.deepsleep(t)
|
||||||
9
ports/esp32/boards/UM_FEATHERS2/mpconfigboard.cmake
Normal file
9
ports/esp32/boards/UM_FEATHERS2/mpconfigboard.cmake
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
set(IDF_TARGET esp32s2)
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
boards/sdkconfig.base
|
||||||
|
boards/sdkconfig.spiram_sx
|
||||||
|
boards/sdkconfig.usb
|
||||||
|
boards/UM_FEATHERS2/sdkconfig.board
|
||||||
|
)
|
||||||
|
|
||||||
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
|
||||||
12
ports/esp32/boards/UM_FEATHERS2/mpconfigboard.h
Normal file
12
ports/esp32/boards/UM_FEATHERS2/mpconfigboard.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#define MICROPY_HW_BOARD_NAME "FeatherS2"
|
||||||
|
#define MICROPY_HW_MCU_NAME "ESP32-S2"
|
||||||
|
|
||||||
|
#define MICROPY_PY_BLUETOOTH (0)
|
||||||
|
#define MICROPY_HW_ENABLE_SDCARD (0)
|
||||||
|
|
||||||
|
#define MICROPY_HW_I2C0_SCL (9)
|
||||||
|
#define MICROPY_HW_I2C0_SDA (8)
|
||||||
|
|
||||||
|
#define MICROPY_HW_SPI1_MOSI (35) // SDO
|
||||||
|
#define MICROPY_HW_SPI1_MISO (37) // SDI
|
||||||
|
#define MICROPY_HW_SPI1_SCK (36)
|
||||||
16
ports/esp32/boards/UM_FEATHERS2/sdkconfig.board
Normal file
16
ports/esp32/boards/UM_FEATHERS2/sdkconfig.board
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
CONFIG_FLASHMODE_QIO=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
|
||||||
|
CONFIG_ESPTOOLPY_AFTER_NORESET=y
|
||||||
|
|
||||||
|
CONFIG_SPIRAM_MEMTEST=
|
||||||
|
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16MiB.csv"
|
||||||
|
#CONFIG_USB_AND_UART=y
|
||||||
|
|
||||||
|
# LWIP
|
||||||
|
CONFIG_LWIP_LOCAL_HOSTNAME="UMFeatherS2"
|
||||||
|
# end of LWIP
|
||||||
2
ports/esp32/boards/UM_TINYPICO/manifest.py
Normal file
2
ports/esp32/boards/UM_TINYPICO/manifest.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
include("$(PORT_DIR)/boards/manifest.py")
|
||||||
|
freeze("modules")
|
||||||
@ -80,7 +80,7 @@ def get_battery_charging():
|
|||||||
# need to be able to cut power to it to minimise power consumption during deep sleep or with general battery powered use
|
# need to be able to cut power to it to minimise power consumption during deep sleep or with general battery powered use
|
||||||
# to minimise unneeded battery drain
|
# to minimise unneeded battery drain
|
||||||
def set_dotstar_power(state):
|
def set_dotstar_power(state):
|
||||||
"""Set the power for the on-board Dostar to allow no current draw when not needed."""
|
"""Set the power for the on-board Dotstar to allow no current draw when not needed."""
|
||||||
# Set the power pin to the inverse of state
|
# Set the power pin to the inverse of state
|
||||||
if state:
|
if state:
|
||||||
Pin(DOTSTAR_PWR, Pin.OUT, None) # Break the PULL_HOLD on the pin
|
Pin(DOTSTAR_PWR, Pin.OUT, None) # Break the PULL_HOLD on the pin
|
||||||
11
ports/esp32/boards/UM_TINYPICO/mpconfigboard.cmake
Normal file
11
ports/esp32/boards/UM_TINYPICO/mpconfigboard.cmake
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
boards/sdkconfig.base
|
||||||
|
boards/sdkconfig.ble
|
||||||
|
boards/sdkconfig.240mhz
|
||||||
|
boards/sdkconfig.spiram
|
||||||
|
boards/UM_TINYPICO/sdkconfig.board
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||||
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
|
||||||
|
endif()
|
||||||
9
ports/esp32/boards/UM_TINYPICO/mpconfigboard.h
Normal file
9
ports/esp32/boards/UM_TINYPICO/mpconfigboard.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#define MICROPY_HW_BOARD_NAME "TinyPICO"
|
||||||
|
#define MICROPY_HW_MCU_NAME "ESP32-PICO-D4"
|
||||||
|
|
||||||
|
#define MICROPY_HW_I2C0_SCL (22)
|
||||||
|
#define MICROPY_HW_I2C0_SDA (21)
|
||||||
|
|
||||||
|
#define MICROPY_HW_SPI1_SCK (18)
|
||||||
|
#define MICROPY_HW_SPI1_MOSI (23)
|
||||||
|
#define MICROPY_HW_SPI1_MISO (19)
|
||||||
@ -2,3 +2,4 @@ CONFIG_FLASHMODE_QIO=y
|
|||||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||||
CONFIG_SPIRAM_SPEED_80M=y
|
CONFIG_SPIRAM_SPEED_80M=y
|
||||||
CONFIG_ESP32_REV_MIN_1=y
|
CONFIG_ESP32_REV_MIN_1=y
|
||||||
|
CONFIG_LWIP_LOCAL_HOSTNAME="UMTinyPICO"
|
||||||
2
ports/esp32/boards/UM_TINYS2/manifest.py
Normal file
2
ports/esp32/boards/UM_TINYS2/manifest.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
include("$(PORT_DIR)/boards/manifest.py")
|
||||||
|
freeze("modules")
|
||||||
82
ports/esp32/boards/UM_TINYS2/modules/tinys2.py
Normal file
82
ports/esp32/boards/UM_TINYS2/modules/tinys2.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# TinyS2 MicroPython Helper Library
|
||||||
|
# 2021 Seon Rozenblum - Unexpected Maker
|
||||||
|
#
|
||||||
|
# Project home:
|
||||||
|
# https://tinys2.io
|
||||||
|
#
|
||||||
|
# 2021-Apr-10 - v0.1 - Initial implementation
|
||||||
|
|
||||||
|
# Import required libraries
|
||||||
|
from micropython import const
|
||||||
|
from machine import Pin, SPI, ADC
|
||||||
|
import machine, time
|
||||||
|
|
||||||
|
# TinyS2 Hardware Pin Assignments
|
||||||
|
|
||||||
|
# Sense Pins
|
||||||
|
VBUS_SENSE = const(21)
|
||||||
|
VBAT_SENSE = const(3)
|
||||||
|
|
||||||
|
|
||||||
|
# RGB LED Pins
|
||||||
|
RGB_DATA = const(1)
|
||||||
|
RGB_PWR = const(2)
|
||||||
|
|
||||||
|
# SPI
|
||||||
|
SPI_MOSI = const(35)
|
||||||
|
SPI_MISO = const(36)
|
||||||
|
SPI_CLK = const(37)
|
||||||
|
|
||||||
|
# I2C
|
||||||
|
I2C_SDA = const(8)
|
||||||
|
I2C_SCL = const(9)
|
||||||
|
|
||||||
|
# DAC
|
||||||
|
DAC1 = const(17)
|
||||||
|
DAC2 = const(18)
|
||||||
|
|
||||||
|
|
||||||
|
# Helper functions
|
||||||
|
def set_pixel_power(state):
|
||||||
|
"""Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep."""
|
||||||
|
Pin(RGB_PWR, Pin.OUT).value(state)
|
||||||
|
|
||||||
|
|
||||||
|
def get_battery_voltage():
|
||||||
|
"""
|
||||||
|
Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage
|
||||||
|
This is an approximation only, but useful to detect if the charge state of the battery is getting low.
|
||||||
|
"""
|
||||||
|
adc = ADC(Pin(VBAT_SENSE)) # Assign the ADC pin to read
|
||||||
|
measuredvbat = adc.read() # Read the value
|
||||||
|
measuredvbat /= 8192 # divide by 8192 as we are using the default ADC voltage range of 0-1V
|
||||||
|
measuredvbat *= 4.2 # Multiply by 4.2V, our reference voltage
|
||||||
|
return round(measuredvbat, 2)
|
||||||
|
|
||||||
|
|
||||||
|
def get_vbus_present():
|
||||||
|
"""Detect if VBUS (5V) power source is present"""
|
||||||
|
return Pin(VBUS_SENSE, Pin.IN).value() == 1
|
||||||
|
|
||||||
|
|
||||||
|
# NeoPixel rainbow colour wheel
|
||||||
|
def rgb_color_wheel(wheel_pos):
|
||||||
|
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
|
||||||
|
wheel_pos = wheel_pos % 255
|
||||||
|
|
||||||
|
if wheel_pos < 85:
|
||||||
|
return 255 - wheel_pos * 3, 0, wheel_pos * 3
|
||||||
|
elif wheel_pos < 170:
|
||||||
|
wheel_pos -= 85
|
||||||
|
return 0, wheel_pos * 3, 255 - wheel_pos * 3
|
||||||
|
else:
|
||||||
|
wheel_pos -= 170
|
||||||
|
return wheel_pos * 3, 255 - wheel_pos * 3, 0
|
||||||
|
|
||||||
|
|
||||||
|
# Go into deep sleep but shut down the RGB LED first to save power
|
||||||
|
# Use this if you want lowest deep sleep current
|
||||||
|
def go_deepsleep(t):
|
||||||
|
"""Deep sleep helper that also powers down the on-board NeoPixel."""
|
||||||
|
set_pixel_power(False)
|
||||||
|
machine.deepsleep(t)
|
||||||
8
ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake
Normal file
8
ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
set(IDF_TARGET esp32s2)
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
boards/sdkconfig.base
|
||||||
|
boards/sdkconfig.spiram_sx
|
||||||
|
boards/sdkconfig.usb
|
||||||
|
)
|
||||||
|
|
||||||
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
||||||
12
ports/esp32/boards/UM_TINYS2/mpconfigboard.h
Normal file
12
ports/esp32/boards/UM_TINYS2/mpconfigboard.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#define MICROPY_HW_BOARD_NAME "TinyS2"
|
||||||
|
#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2"
|
||||||
|
|
||||||
|
#define MICROPY_PY_BLUETOOTH (0)
|
||||||
|
#define MICROPY_HW_ENABLE_SDCARD (0)
|
||||||
|
|
||||||
|
#define MICROPY_HW_I2C0_SCL (9)
|
||||||
|
#define MICROPY_HW_I2C0_SDA (8)
|
||||||
|
|
||||||
|
#define MICROPY_HW_SPI1_MOSI (35)
|
||||||
|
#define MICROPY_HW_SPI1_MISO (36)
|
||||||
|
#define MICROPY_HW_SPI1_SCK (37)
|
||||||
6
ports/esp32/boards/UM_TINYS2/sdkconfig.board
Normal file
6
ports/esp32/boards/UM_TINYS2/sdkconfig.board
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
CONFIG_FLASHMODE_QIO=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||||
|
CONFIG_USB_AND_UART=y
|
||||||
|
# LWIP
|
||||||
|
CONFIG_LWIP_LOCAL_HOSTNAME="UMTinyS2"
|
||||||
|
# end of LWIP
|
||||||
@ -1,6 +1,7 @@
|
|||||||
include("manifest.py")
|
include("manifest.py")
|
||||||
|
|
||||||
freeze("$(MPY_LIB_DIR)/upysh", "upysh.py")
|
freeze("$(MPY_LIB_DIR)/python-ecosys/urequests", "urequests.py")
|
||||||
freeze("$(MPY_LIB_DIR)/urequests", "urequests.py")
|
|
||||||
freeze("$(MPY_LIB_DIR)/umqtt.simple", "umqtt/simple.py")
|
freeze("$(MPY_LIB_DIR)/micropython/upysh", "upysh.py")
|
||||||
freeze("$(MPY_LIB_DIR)/umqtt.robust", "umqtt/robust.py")
|
freeze("$(MPY_LIB_DIR)/micropython/umqtt.simple", "umqtt/simple.py")
|
||||||
|
freeze("$(MPY_LIB_DIR)/micropython/umqtt.robust", "umqtt/robust.py")
|
||||||
|
|||||||
11
ports/esp32/boards/sdkconfig.spiram_sx
Normal file
11
ports/esp32/boards/sdkconfig.spiram_sx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# MicroPython on ESP32-S2 and ESP32-PAD1_subscript_3, ESP IDF configuration with SPIRAM support
|
||||||
|
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
|
||||||
|
CONFIG_SPIRAM_TYPE_AUTO=y
|
||||||
|
CONFIG_DEFAULT_PSRAM_CLK_IO=30
|
||||||
|
CONFIG_DEFAULT_PSRAM_CS_IO=26
|
||||||
|
CONFIG_SPIRAM_SPEED_80M=y
|
||||||
|
CONFIG_SPIRAM=y
|
||||||
|
CONFIG_SPIRAM_BOOT_INIT=y
|
||||||
|
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
|
||||||
|
CONFIG_SPIRAM_USE_MEMMAP=y
|
||||||
|
CONFIG_SPIRAM_MEMTEST=y
|
||||||
@ -96,7 +96,7 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
|||||||
self->carrier_freq = carrier_freq;
|
self->carrier_freq = carrier_freq;
|
||||||
self->loop_en = false;
|
self->loop_en = false;
|
||||||
|
|
||||||
rmt_config_t config;
|
rmt_config_t config = {0};
|
||||||
config.rmt_mode = RMT_MODE_TX;
|
config.rmt_mode = RMT_MODE_TX;
|
||||||
config.channel = (rmt_channel_t)self->channel_id;
|
config.channel = (rmt_channel_t)self->channel_id;
|
||||||
config.gpio_num = self->pin;
|
config.gpio_num = self->pin;
|
||||||
|
|||||||
@ -11,9 +11,17 @@
|
|||||||
|
|
||||||
void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing) {
|
void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing) {
|
||||||
uint8_t *p, *end, pix, mask;
|
uint8_t *p, *end, pix, mask;
|
||||||
uint32_t t, time0, time1, period, c, startTime, pinMask;
|
uint32_t t, time0, time1, period, c, startTime, pinMask, gpio_reg_set, gpio_reg_clear;
|
||||||
|
|
||||||
pinMask = 1 << pin;
|
if (pin < 32) {
|
||||||
|
pinMask = 1 << pin;
|
||||||
|
gpio_reg_set = GPIO_OUT_W1TS_REG;
|
||||||
|
gpio_reg_clear = GPIO_OUT_W1TC_REG;
|
||||||
|
} else {
|
||||||
|
pinMask = 1 << (pin - 32);
|
||||||
|
gpio_reg_set = GPIO_OUT1_W1TS_REG;
|
||||||
|
gpio_reg_clear = GPIO_OUT1_W1TC_REG;
|
||||||
|
}
|
||||||
p = pixels;
|
p = pixels;
|
||||||
end = p + numBytes;
|
end = p + numBytes;
|
||||||
pix = *p++;
|
pix = *p++;
|
||||||
@ -42,12 +50,12 @@ void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numByte
|
|||||||
while (((c = mp_hal_ticks_cpu()) - startTime) < period) {
|
while (((c = mp_hal_ticks_cpu()) - startTime) < period) {
|
||||||
; // Wait for bit start
|
; // Wait for bit start
|
||||||
}
|
}
|
||||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, pinMask); // Set high
|
GPIO_REG_WRITE(gpio_reg_set, pinMask); // Set high
|
||||||
startTime = c; // Save start time
|
startTime = c; // Save start time
|
||||||
while (((c = mp_hal_ticks_cpu()) - startTime) < t) {
|
while (((c = mp_hal_ticks_cpu()) - startTime) < t) {
|
||||||
; // Wait high duration
|
; // Wait high duration
|
||||||
}
|
}
|
||||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, pinMask); // Set low
|
GPIO_REG_WRITE(gpio_reg_clear, pinMask); // Set low
|
||||||
if (!(mask >>= 1)) { // Next bit/byte
|
if (!(mask >>= 1)) { // Next bit/byte
|
||||||
if (p >= end) {
|
if (p >= end) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user