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.
|
||||
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
|
||||
*.exe
|
||||
|
||||
lextab.py
|
||||
yacctab.py
|
||||
|
||||
# Packages
|
||||
############
|
||||
|
||||
@ -55,5 +58,6 @@ ports/javascript/node_modules
|
||||
######################
|
||||
genrst/
|
||||
|
||||
lextab.py
|
||||
yacctab.py
|
||||
# MacOS desktop metadata files
|
||||
######################
|
||||
.DS_Store
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -7,7 +7,7 @@
|
||||
url = https://github.com/atgreen/libffi
|
||||
[submodule "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"]
|
||||
path = lib/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
|
||||
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>`_
|
||||
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/
|
||||
└──examples/
|
||||
|
||||
@ -58,7 +58,7 @@ The :mod:`esp32` module::
|
||||
import esp32
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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)
|
||||
----------------------------
|
||||
|
||||
@ -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() # 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
|
||||
---------------
|
||||
|
||||
@ -386,6 +428,21 @@ Notes:
|
||||
|
||||
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
|
||||
---
|
||||
|
||||
@ -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
|
||||
sample the temperature.
|
||||
|
||||
NeoPixel driver
|
||||
---------------
|
||||
NeoPixel and APA106 driver
|
||||
--------------------------
|
||||
|
||||
Use the ``neopixel`` module::
|
||||
Use the ``neopixel`` and ``apa106`` modules::
|
||||
|
||||
from machine import Pin
|
||||
from neopixel import NeoPixel
|
||||
@ -444,6 +501,13 @@ Use the ``neopixel`` module::
|
||||
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]
|
||||
|
||||
For low-level driving of a NeoPixel::
|
||||
|
||||
import esp
|
||||
@ -455,6 +519,7 @@ For low-level driving of a NeoPixel::
|
||||
400kHz) devices by passing ``timing=0`` when constructing the
|
||||
``NeoPixel`` object.
|
||||
|
||||
APA102 (DotStar) uses a different driver as it has an additional clock pin.
|
||||
|
||||
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.
|
||||
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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -153,25 +163,26 @@ SSL/TLS limitations
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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:
|
||||
|
||||
1. No support for Diffie-Hellman (DH) key exchange and Elliptic-curve
|
||||
cryptography (ECC). This means it can't work with sites which force
|
||||
the use of these features (it works ok with classic RSA certificates).
|
||||
cryptography (ECC). This means it can't work with sites which require
|
||||
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
|
||||
sending and receiving, which leads to considerable memory saving and
|
||||
works well with protocols like HTTP. But there may be problems with
|
||||
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
|
||||
(these may be lifted in the future):
|
||||
|
||||
3. Optimized RSA algorithms are not enabled, which may lead to slow
|
||||
SSL handshakes.
|
||||
4. Stored sessions are not supported (may allow faster repeated connections
|
||||
to the same site in some circumstances).
|
||||
4. Session Reuse is not enabled, which means every connection must undergo
|
||||
the full, expensive SSL handshake.
|
||||
|
||||
Besides axTLS specific limitations described above, there's another generic
|
||||
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.
|
||||
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 .
|
||||
The smaller buffer hower means that some sites can't be accessed using
|
||||
it, and it's not possible to stream large amounts of data.
|
||||
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. 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
|
||||
``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).
|
||||
7. There is no support for client certificates (scheduled to be fixed in
|
||||
1.9.4 release).
|
||||
|
||||
@ -58,7 +58,7 @@ The :mod:`network` module::
|
||||
wlan.scan() # scan for access points
|
||||
wlan.isconnected() # check if the station is connected to an AP
|
||||
wlan.connect('essid', 'password') # connect to an AP
|
||||
wlan.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
|
||||
|
||||
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
|
||||
``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)
|
||||
-----------------
|
||||
|
||||
@ -293,6 +297,17 @@ See :ref:`machine.RTC <machine.RTC>` ::
|
||||
(using a custom handler), `RTC.init()` and `RTC.deinit()` are
|
||||
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
|
||||
---------------
|
||||
|
||||
@ -409,6 +424,20 @@ The DHT driver is implemented in software and works on all pins::
|
||||
d.temperature() # eg. 23.6 (°C)
|
||||
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)
|
||||
----------------------------------------
|
||||
|
||||
|
||||
@ -31,4 +31,5 @@ to `<https://www.python.org>`__.
|
||||
neopixel.rst
|
||||
apa102.rst
|
||||
dht.rst
|
||||
ssd1306.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
|
||||
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
|
||||
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
|
||||
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
|
||||
-------------
|
||||
|
||||
|
||||
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
|
||||
esp8266/quickref.rst
|
||||
esp32/quickref.rst
|
||||
rp2/quickref.rst
|
||||
wipy/quickref.rst
|
||||
unix/quickref.rst
|
||||
|
||||
@ -176,10 +176,6 @@ Exceptions
|
||||
|
||||
.. 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:: 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
|
||||
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
|
||||
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.
|
||||
|
||||
``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
|
||||
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
|
||||
defines a baseline operation of executing a callback with a given period
|
||||
(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
|
||||
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
|
||||
defines a baseline operation of executing a callback with a given period
|
||||
(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
|
||||
Timer callbacks.
|
||||
@ -115,7 +115,7 @@ Methods
|
||||
|
||||
.. 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:
|
||||
|
||||
- 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.
|
||||
|
||||
.. 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
|
||||
---------------------------
|
||||
|
||||
@ -56,9 +64,11 @@ Interrupt 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()
|
||||
|
||||
@ -167,6 +177,7 @@ Classes
|
||||
machine.Pin.rst
|
||||
machine.Signal.rst
|
||||
machine.ADC.rst
|
||||
machine.PWM.rst
|
||||
machine.UART.rst
|
||||
machine.SPI.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
|
||||
- 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
|
||||
------------
|
||||
|
||||
@ -26,7 +26,7 @@ For this example to work the WIZnet5x00 module must have the following connectio
|
||||
- nSS connected to X5
|
||||
- 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
|
||||
------------
|
||||
|
||||
@ -55,7 +55,7 @@ parameter should be `id`.
|
||||
Activate ("up") or deactivate ("down") the network interface, if
|
||||
a boolean argument is passed. Otherwise, query current state if
|
||||
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).
|
||||
|
||||
.. 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.
|
||||
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(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.
|
||||
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(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)``
|
||||
|
||||
@ -98,11 +98,11 @@ Class 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:
|
||||
|
||||
- ``mode`` can be one of:
|
||||
- *mode* can be one of:
|
||||
|
||||
- ``Pin.IN`` - configure the pin for input;
|
||||
- ``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.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_UP`` - enable the pull-up 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
|
||||
of one of the alternate functions associated with a pin.
|
||||
- *value* if not None will set the port output value before enabling the 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``.
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ Constructors
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
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(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.
|
||||
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(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
|
||||
|
||||
@ -126,7 +126,7 @@ Power related functions
|
||||
- pclk2: frequency of the APB2 bus
|
||||
|
||||
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
|
||||
not all values are supported and the largest supported frequency not greater
|
||||
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
|
||||
|
||||
``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)``.
|
||||
|
||||
.. data:: PTR
|
||||
|
||||
@ -16,13 +16,13 @@ Constants
|
||||
|
||||
Error codes, based on ANSI C/POSIX standard. All error codes start with
|
||||
"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::
|
||||
|
||||
try:
|
||||
uos.mkdir("my_dir")
|
||||
except OSError as exc:
|
||||
if exc.args[0] == uerrno.EEXIST:
|
||||
if exc.errno == uerrno.EEXIST:
|
||||
print("Directory already exists")
|
||||
|
||||
.. data:: errorcode
|
||||
|
||||
@ -6,9 +6,11 @@
|
||||
|
||||
|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
|
||||
---------
|
||||
@ -19,8 +21,10 @@ Functions
|
||||
|
||||
.. function:: heappop(heap)
|
||||
|
||||
Pop the first item from the ``heap``, and return it. Raises IndexError if
|
||||
heap is empty.
|
||||
Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if
|
||||
``heap`` is empty.
|
||||
|
||||
The returned item will be the smallest item in the ``heap``.
|
||||
|
||||
.. function:: heapify(x)
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ Conceptual hierarchy
|
||||
Conceptual hierarchy of stream base classes is simplified in MicroPython,
|
||||
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
|
||||
classifications) in CPython. In MicroPython, they are somewhat simplified
|
||||
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,
|
||||
it still provides for no-short-operations streams. Whether there will
|
||||
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
|
||||
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
|
||||
be a port-specific class, where such a need is governed by hardware
|
||||
peculiarities.
|
||||
|
||||
The no-short-operations behavior gets tricky in case of non-blocking
|
||||
streams, blocking vs non-blocking behavior being another CPython dichotomy,
|
||||
The no-short-operations behaviour gets tricky in case of non-blocking
|
||||
streams, blocking vs non-blocking behaviour being another CPython dichotomy,
|
||||
fully supported by MicroPython. Non-blocking streams never wait for
|
||||
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
|
||||
|
||||
@ -87,11 +87,11 @@ Methods
|
||||
`callee-owned tuple`. This function provides an efficient, allocation-free
|
||||
way to poll on streams.
|
||||
|
||||
If *flags* is 1, one-shot behavior for events is employed: streams for
|
||||
If *flags* is 1, one-shot behaviour for events is employed: streams for
|
||||
which events happened will have their event masks automatically reset
|
||||
(equivalent to ``poll.modify(obj, 0)``), so new events for such a stream
|
||||
won't be processed until new mask is set with `poll.modify()`. This
|
||||
behavior is useful for asynchronous I/O schedulers.
|
||||
behaviour is useful for asynchronous I/O schedulers.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
@ -222,7 +222,7 @@ Methods
|
||||
Unlike `send()`, this method will try to send all of data, by sending data
|
||||
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
|
||||
has the same "no short writes" policy for blocking sockets, and will return
|
||||
number of bytes sent on non-blocking sockets.
|
||||
|
||||
@ -13,7 +13,8 @@ facilities for network sockets, both client-side and server-side.
|
||||
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),
|
||||
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
|
||||
|
||||
@ -173,7 +173,7 @@ Functions
|
||||
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
|
||||
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.
|
||||
|
||||
`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.
|
||||
3. The microcontroller starts executing the special 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.
|
||||
4. Your callback function is executed until it finishes, returning control
|
||||
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/>
|
||||
<span class="linkdescr">pinout for ESP32-based boards, snippets of useful code, and a tutorial</span>
|
||||
</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">
|
||||
<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>
|
||||
|
||||
@ -112,7 +112,7 @@ void cyw43_deinit(cyw43_t *self) {
|
||||
self->itf_state = 0;
|
||||
|
||||
// Disable async polling
|
||||
SDMMC1->MASK &= ~SDMMC_MASK_SDIOITIE;
|
||||
sdio_enable_irq(false);
|
||||
cyw43_poll = NULL;
|
||||
|
||||
#ifdef pyb_pin_WL_RFSW_VDD
|
||||
@ -164,7 +164,7 @@ STATIC int cyw43_ensure_up(cyw43_t *self) {
|
||||
cyw43_sleep = CYW43_SLEEP_MAX;
|
||||
cyw43_poll = cyw43_poll_func;
|
||||
#if USE_SDIOIT
|
||||
SDMMC1->MASK |= SDMMC_MASK_SDIOITIE;
|
||||
sdio_enable_irq(true);
|
||||
#else
|
||||
extern void extint_set(const pin_obj_t *pin, uint32_t mode);
|
||||
extint_set(pyb_pin_WL_HOST_WAKE, GPIO_MODE_IT_FALLING);
|
||||
@ -209,7 +209,7 @@ STATIC void cyw43_poll_func(void) {
|
||||
}
|
||||
|
||||
#if USE_SDIOIT
|
||||
SDMMC1->MASK |= SDMMC_MASK_SDIOITIE;
|
||||
sdio_enable_irq(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -227,10 +227,7 @@ int cyw43_cb_read_host_interrupt_pin(void *cb_data) {
|
||||
void cyw43_cb_ensure_awake(void *cb_data) {
|
||||
cyw43_sleep = CYW43_SLEEP_MAX;
|
||||
#if !USE_SDIOIT
|
||||
if (__HAL_RCC_SDMMC1_IS_CLK_DISABLED()) {
|
||||
__HAL_RCC_SDMMC1_CLK_ENABLE(); // enable SDIO peripheral
|
||||
sdio_enable_high_speed_4bit();
|
||||
}
|
||||
sdio_reenable();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ STATIC void cywbt_wait_cts_low(void) {
|
||||
}
|
||||
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) {
|
||||
@ -149,10 +149,14 @@ STATIC int cywbt_download_firmware(const uint8_t *firmware) {
|
||||
}
|
||||
|
||||
// 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);
|
||||
#endif
|
||||
mp_hal_delay_ms(10); // give some time for CTS to go high
|
||||
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)
|
||||
#endif
|
||||
|
||||
mp_bluetooth_hci_uart_set_baudrate(115200);
|
||||
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_low(pyb_pin_BT_DEV_WAKE);
|
||||
|
||||
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||
// 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_high(pyb_pin_WL_GPIO_4); // Turn the RF-switch on
|
||||
#endif
|
||||
|
||||
uint8_t buf[256];
|
||||
|
||||
|
||||
@ -37,12 +37,12 @@ class SSD1306(framebuf.FrameBuffer):
|
||||
|
||||
def init_display(self):
|
||||
for cmd in (
|
||||
SET_DISP | 0x00, # off
|
||||
SET_DISP, # display off
|
||||
# address setting
|
||||
SET_MEM_ADDR,
|
||||
0x00, # horizontal
|
||||
# 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_MUX_RATIO,
|
||||
self.height - 1,
|
||||
@ -66,14 +66,14 @@ class SSD1306(framebuf.FrameBuffer):
|
||||
# charge pump
|
||||
SET_CHARGE_PUMP,
|
||||
0x10 if self.external_vcc else 0x14,
|
||||
SET_DISP | 0x01,
|
||||
SET_DISP | 0x01, # display on
|
||||
): # on
|
||||
self.write_cmd(cmd)
|
||||
self.fill(0)
|
||||
self.show()
|
||||
|
||||
def poweroff(self):
|
||||
self.write_cmd(SET_DISP | 0x00)
|
||||
self.write_cmd(SET_DISP)
|
||||
|
||||
def poweron(self):
|
||||
self.write_cmd(SET_DISP | 0x01)
|
||||
@ -85,6 +85,10 @@ class SSD1306(framebuf.FrameBuffer):
|
||||
def invert(self, invert):
|
||||
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):
|
||||
x0 = 0
|
||||
x1 = self.width - 1
|
||||
|
||||
@ -176,6 +176,7 @@ class SDCard:
|
||||
self.spi.readinto(self.tokenbuf, 0xFF)
|
||||
if self.tokenbuf[0] == _TOKEN_DATA:
|
||||
break
|
||||
time.sleep_ms(1)
|
||||
else:
|
||||
self.cs(1)
|
||||
raise OSError("timeout waiting for response")
|
||||
|
||||
@ -34,38 +34,10 @@
|
||||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
|
||||
/// \module uctypes - Access data structures in memory
|
||||
///
|
||||
/// The module allows to define layout of raw data structure (using terms
|
||||
/// of C language), and then access memory buffers using this definition.
|
||||
/// 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
|
||||
// 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 also provides convenience functions to access memory buffers
|
||||
// contained in Python objects or wrap memory buffers in Python objects.
|
||||
|
||||
#define LAYOUT_LITTLE_ENDIAN (0)
|
||||
#define LAYOUT_BIG_ENDIAN (1)
|
||||
@ -75,6 +47,7 @@
|
||||
#define BITF_LEN_BITS 5
|
||||
#define BITF_OFF_BITS 5
|
||||
#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
|
||||
#error Invalid encoding field length
|
||||
#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;
|
||||
if (t->len == 2) {
|
||||
// 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) {
|
||||
*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_uint_t val_type = GET_TYPE(offset, 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) {
|
||||
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
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) {
|
||||
uint bit_offset = (offset >> 17) & 31;
|
||||
uint bit_len = (offset >> 22) & 31;
|
||||
offset &= (1 << 17) - 1;
|
||||
uint bit_offset = (offset >> OFFSET_BITS) & 31;
|
||||
uint bit_len = (offset >> LEN_BITS) & 31;
|
||||
offset &= (1 << OFFSET_BITS) - 1;
|
||||
mp_uint_t val;
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
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_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
// printf("agg type=%d offset=%x\n", agg_type, offset);
|
||||
|
||||
switch (agg_type) {
|
||||
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->addr = self->addr + offset;
|
||||
o->flags = self->flags;
|
||||
// printf("PTR/ARR base addr=%p\n", o->addr);
|
||||
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
|
||||
}
|
||||
} 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) {
|
||||
return get_unaligned(val_type, p, self->flags);
|
||||
} else {
|
||||
@ -647,9 +616,8 @@ STATIC mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \function addressof()
|
||||
/// Return address of object's data (applies to object providing buffer
|
||||
/// interface).
|
||||
// addressof()
|
||||
// Return address of object's data (applies to objects providing the buffer interface).
|
||||
STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
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);
|
||||
|
||||
/// \function bytearray_at()
|
||||
/// Capture memory at given address of given size as bytearray. Memory is
|
||||
/// captured by reference (and thus memory pointed by bytearray may change
|
||||
/// or become invalid at later time). Use bytes_at() to capture by value.
|
||||
// bytearray_at()
|
||||
// Capture memory at given address of given size as bytearray.
|
||||
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));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
|
||||
|
||||
/// \function bytes_at()
|
||||
/// Capture memory at given address of given size as bytes. Memory is
|
||||
/// captured by value, i.e. copied. Use bytearray_at() to capture by reference
|
||||
/// ("zero copy").
|
||||
// bytes_at()
|
||||
// Capture memory at given address of given size as bytes.
|
||||
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));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
|
||||
|
||||
|
||||
STATIC const mp_obj_type_t uctypes_struct_type = {
|
||||
{ &mp_type_type },
|
||||
.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_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) },
|
||||
/// \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) },
|
||||
/// \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) },
|
||||
|
||||
/// \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)) },
|
||||
|
||||
/// \constant UINT8 - uint8_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, 4)) },
|
||||
/// \constant INT8 - int8_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, 4)) },
|
||||
/// \constant UINT16 - uint16_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) },
|
||||
/// \constant INT16 - int16_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },
|
||||
/// \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_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, 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, VAL_TYPE_BITS)) },
|
||||
{ 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, VAL_TYPE_BITS)) },
|
||||
{ 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, VAL_TYPE_BITS)) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(22) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(OFFSET_BITS) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(LEN_BITS) },
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, 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, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_UCTYPES_NATIVE_C_TYPES
|
||||
// C native type aliases. These depend on GCC-compatible predefined
|
||||
// preprocessor macros.
|
||||
#if __SIZEOF_SHORT__ == 2
|
||||
{ MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, 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, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#if __SIZEOF_INT__ == 4
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, 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, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#if __SIZEOF_LONG__ == 4
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, 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, VAL_TYPE_BITS)) },
|
||||
#elif __SIZEOF_LONG__ == 8
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 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, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#if __SIZEOF_LONG_LONG__ == 8
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 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, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#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_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uctypes = {
|
||||
|
||||
@ -60,9 +60,16 @@
|
||||
|
||||
typedef struct _mp_obj_hash_t {
|
||||
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;
|
||||
|
||||
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
|
||||
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_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
mbedtls_sha256_init((mbedtls_sha256_context *)&o->state);
|
||||
mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0);
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 32);
|
||||
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_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
sha256_init((CRYAL_SHA256_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
|
||||
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_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
SHA1_Init((SHA1_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, SHA1_SIZE);
|
||||
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_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
mbedtls_sha1_init((mbedtls_sha1_context *)o->state);
|
||||
mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state);
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 20);
|
||||
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_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(MD5_CTX));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
MD5_Init((MD5_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, MD5_SIZE);
|
||||
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_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
mbedtls_md5_init((mbedtls_md5_context *)o->state);
|
||||
mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state);
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
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) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 16);
|
||||
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) {
|
||||
int n = mp_obj_get_int(num_in);
|
||||
if (n > 32 || n == 0) {
|
||||
mp_raise_ValueError(NULL);
|
||||
if (n > 32 || n < 0) {
|
||||
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;
|
||||
// Beware of C undefined behavior when shifting by >= than bit size
|
||||
|
||||
@ -40,10 +40,6 @@
|
||||
// Flags for poll()
|
||||
#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 {
|
||||
mp_obj_t obj;
|
||||
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;
|
||||
}
|
||||
|
||||
/// \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) {
|
||||
// get array data from tuple/list arguments
|
||||
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);
|
||||
|
||||
/// \class Poll - poll class
|
||||
|
||||
typedef struct _mp_obj_poll_t {
|
||||
mp_obj_base_t base;
|
||||
mp_map_t poll_map;
|
||||
@ -190,7 +184,7 @@ typedef struct _mp_obj_poll_t {
|
||||
mp_obj_t ret_tuple;
|
||||
} 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) {
|
||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
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);
|
||||
|
||||
/// \method unregister(obj)
|
||||
// unregister(obj)
|
||||
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_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);
|
||||
|
||||
/// \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) {
|
||||
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);
|
||||
@ -348,7 +342,7 @@ STATIC const mp_obj_type_t mp_type_poll = {
|
||||
.locals_dict = (void *)&poll_locals_dict,
|
||||
};
|
||||
|
||||
/// \function poll()
|
||||
// poll()
|
||||
STATIC mp_obj_t select_poll(void) {
|
||||
mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t);
|
||||
poll->base.type = &mp_type_poll;
|
||||
|
||||
@ -82,7 +82,7 @@ async def open_connection(host, port):
|
||||
try:
|
||||
s.connect(ai[-1])
|
||||
except OSError as er:
|
||||
if er.args[0] != EINPROGRESS:
|
||||
if er.errno != EINPROGRESS:
|
||||
raise er
|
||||
yield core._io_queue.queue_write(s)
|
||||
return ss, ss
|
||||
@ -112,7 +112,6 @@ class Server:
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
s.bind(ai[-1])
|
||||
s.listen(backlog)
|
||||
self.task = core.cur_task
|
||||
# Accept incoming connections
|
||||
while True:
|
||||
try:
|
||||
@ -135,7 +134,7 @@ class Server:
|
||||
# TODO could use an accept-callback on socket read activity instead of creating a task
|
||||
async def start_server(cb, host, port, backlog=5):
|
||||
s = Server()
|
||||
core.create_task(s._serve(cb, host, port, backlog))
|
||||
s.task = core.create_task(s._serve(cb, host, port, backlog))
|
||||
return s
|
||||
|
||||
|
||||
|
||||
@ -133,7 +133,7 @@ int mp_uos_dupterm_rx_chr(void) {
|
||||
nlr_pop();
|
||||
if (buf[0] == mp_interrupt_char) {
|
||||
// Signal keyboard interrupt to be raised as soon as the VM resumes
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
return -2;
|
||||
}
|
||||
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);
|
||||
|
||||
/// Change current directory.
|
||||
// Change current directory.
|
||||
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);
|
||||
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);
|
||||
|
||||
/// Get the current directory.
|
||||
// Get the current directory.
|
||||
STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||
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);
|
||||
|
||||
/// \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) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_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,
|
||||
// so force the GC to be unlocked to help the user debug what went wrong.
|
||||
if (MP_STATE_MEM(gc_lock_depth) != 0) {
|
||||
MP_STATE_MEM(gc_lock_depth) = 0;
|
||||
if (MP_STATE_THREAD(gc_lock_depth) != 0) {
|
||||
MP_STATE_THREAD(gc_lock_depth) = 0;
|
||||
}
|
||||
|
||||
vstr_reset(&line);
|
||||
|
||||
@ -41,7 +41,6 @@ extern pyexec_mode_kind_t pyexec_mode_kind;
|
||||
extern int pyexec_system_exit;
|
||||
|
||||
#define PYEXEC_FORCED_EXIT (0x100)
|
||||
#define PYEXEC_SWITCH_MODE (0x200)
|
||||
|
||||
int pyexec_raw_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)
|
||||
*
|
||||
* Copyright (c) 2020 Philipp Ebensberger
|
||||
* 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
|
||||
@ -23,11 +23,29 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* 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[] = {
|
||||
PIN_AF(GPIOMUX_IO11, PIN_AF_MODE_ALT5, GPIO1, 0x10B0U),
|
||||
};
|
||||
To use semi-hosting for a replacement UART:
|
||||
- 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
|
||||
|
||||
# Set makefile-level MicroPython feature configurations.
|
||||
MICROPY_ROM_TEXT_COMPRESSION ?= 1
|
||||
MICROPY_ROM_TEXT_COMPRESSION ?= 0
|
||||
|
||||
# Define toolchain and other tools.
|
||||
CROSS_COMPILE ?= arm-none-eabi-
|
||||
|
||||
@ -18,4 +18,4 @@ compiled and executed when the firmware starts. They produce output on the
|
||||
system's stdout.
|
||||
|
||||
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
|
||||
#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_MODULE_GETATTR (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);
|
||||
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
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
} else { // there's always a read buffer available
|
||||
uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN;
|
||||
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 (telnet_data.state == E_TELNET_STE_LOGGED_IN && *_str == mp_interrupt_char) {
|
||||
// raise a keyboard exception
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
(*len)--;
|
||||
_str++;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# 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(MICROPY_PORT_DIR ${CMAKE_SOURCE_DIR})
|
||||
|
||||
@ -26,6 +26,10 @@ endif
|
||||
|
||||
IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -B $(BUILD) $(CMAKE_ARGS)
|
||||
|
||||
ifdef FROZEN_MANIFEST
|
||||
IDFPY_FLAGS += -D MICROPY_FROZEN_MANIFEST=$(FROZEN_MANIFEST)
|
||||
endif
|
||||
|
||||
all:
|
||||
idf.py $(IDFPY_FLAGS) build
|
||||
@$(PYTHON) makeimg.py \
|
||||
@ -34,7 +38,7 @@ all:
|
||||
$(BUILD)/micropython.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:
|
||||
idf.py $(IDFPY_FLAGS) fullclean
|
||||
|
||||
@ -2,5 +2,6 @@ set(SDKCONFIG_DEFAULTS
|
||||
boards/sdkconfig.base
|
||||
boards/sdkconfig.ble
|
||||
)
|
||||
|
||||
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_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
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
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
|
||||
# to minimise unneeded battery drain
|
||||
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
|
||||
if state:
|
||||
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_SPIRAM_SPEED_80M=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")
|
||||
|
||||
freeze("$(MPY_LIB_DIR)/upysh", "upysh.py")
|
||||
freeze("$(MPY_LIB_DIR)/urequests", "urequests.py")
|
||||
freeze("$(MPY_LIB_DIR)/umqtt.simple", "umqtt/simple.py")
|
||||
freeze("$(MPY_LIB_DIR)/umqtt.robust", "umqtt/robust.py")
|
||||
freeze("$(MPY_LIB_DIR)/python-ecosys/urequests", "urequests.py")
|
||||
|
||||
freeze("$(MPY_LIB_DIR)/micropython/upysh", "upysh.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->loop_en = false;
|
||||
|
||||
rmt_config_t config;
|
||||
rmt_config_t config = {0};
|
||||
config.rmt_mode = RMT_MODE_TX;
|
||||
config.channel = (rmt_channel_t)self->channel_id;
|
||||
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) {
|
||||
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;
|
||||
end = p + numBytes;
|
||||
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) {
|
||||
; // 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
|
||||
while (((c = mp_hal_ticks_cpu()) - startTime) < t) {
|
||||
; // 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 (p >= end) {
|
||||
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