The ports esp32, mimxrt, rp2 and samd all shared exactly the same
implementation of machine.disable_irq() and machine.enable_irq(),
implemented in terms of MICROPY_{BEGIN,END}_ATOMIC_SECTION. This commit
factors these implementations into extmod/modmachine.c.
The cc3200, esp8266, nrf, renesas-ra and stm32 ports do not yet use this
common implementation.
Signed-off-by: Damien George <damien@micropython.org>
Minor changes for consistency are:
- nrf gains: unique_id(), freq() [they do nothing]
- samd: deepsleep() now resets after calling lightsleep()
- esp32: lightsleep()/deepsleep() no longer take kw arg "sleep", instead
it's positional to match others. also, passing 0 here will now do a 0ms
sleep instead of acting like nothing was passed.
reset_cause() no longer takes any args (before it would just ignore them)
- mimxrt: freq() with an argument and lightsleep() both raise
NotImplementedError
Signed-off-by: Damien George <damien@micropython.org>
And use it in all ports. The ports are unchanged, except esp8266 which now
just returns None from this function instead of the time elapsed (to match
other ports), and qemu-arm which gains this function.
Signed-off-by: Damien George <damien@micropython.org>
This is a code factoring to have the dict for the machine module in one
location, and all the ports use that same dict. The machine.soft_reset()
function implementation is also factored because it's the same for all
ports that did already implement it. Eventually more functions/bindings
can be factored.
All ports remain functionally the same, except:
- cc3200 port: gains soft_reset, mem8, mem16, mem32, Signal; loses POWER_ON
(which was a legacy constant, replaced long ago by PWRON_RESET)
- nrf port: gains Signal
- qemu-arm port: gains soft_reset
- unix port: gains soft_reset
- zephyr port: gains soft_reset, mem8, mem16, mem32
Signed-off-by: Damien George <damien@micropython.org>
The main motivation for doing this was to reduce the latency when the
system is woken by a USB interrupt. The best_effort_wfe_or_timeout()
function calls into the pico-sdk dynamic timer framework which sets up a
new dynamic timer instance each time, and then has to tear it down before
continuing after a WFE.
Testing Python interrupt latency, it seems to be improved by about 12us
(from average of 46us to 34us running a Pin IRQ). C-based "scheduled
nodes" should see even lower latency.
This work was funded through GitHub Sponsors.
Signed-off-by: Angus Gratton <angus@redyak.com.au>
The contents of machine_mem.h, machine_i2c.h and machine_spi.h have been
moved into extmod/modmachine.h.
Signed-off-by: Damien George <damien@micropython.org>
The contents of machine_bitstream.h, machine_pinbase.h, machine_pulse.h and
machine_signal.h have been moved into extmod/modmachine.h.
Signed-off-by: Damien George <damien@micropython.org>
This is a code factoring to have the Python bindings in one location, and
all the ports use those same bindings. For all ports except the two listed
below there is no functional change.
The nrf port has UART.sendbreak() removed, but this method previously did
nothing.
The zephyr port has the following methods added:
- UART.init(): supports setting timeout and timeout_char.
- UART.deinit(): does nothing, just returns None.
- UART.flush(): raises OSError(EINVAL) because it's not implemented.
- UART.any() and UART.txdone(): raise NotImplementedError.
Signed-off-by: Damien George <damien@micropython.org>
No functional change, just code factoring to have the Python bindings in
one location, and all the ports use those same bindings.
Signed-off-by: Damien George <damien@micropython.org>
With public declarations moved to extmod/modmachine.h. It's now mandatory
for a port to define MICROPY_PY_MACHINE_PWM_INCLUDEFILE if it enables
MICROPY_PY_MACHINE_PWM. This follows how extmod/machine_wdt.c works.
All ports have been updated to work with this modified scheme.
Signed-off-by: Damien George <damien@micropython.org>
There are currently 7 ports that implement machine.WDT and a lot of code is
duplicated across these implementations. This commit factors the common
parts of all these implementations to a single location in
extmod/machine_wdt.c. This common code provides the top-level Python
bindings (class and method wrappers), and then each port implements the
back end specific to that port.
With this refactor the ports remain functionally the same except for:
- The esp8266 WDT constructor now takes keyword arguments, and accepts the
"timeout" argument but raises an exception if it's not the default value
(this port doesn't support changing the timeout).
- The mimxrt and samd ports now interpret the argument to WDT.timeout_ms()
as signed and if it's negative truncate it to the minimum timeout (rather
than it being unsigned and a negative value truncating to the maximum
timeout).
Signed-off-by: Damien George <damien@micropython.org>
While cyw43 is deinitialized, an interrupt occurs. That is handled with
these lines: ports/rp2/mpnetworkport.c#L59-L61 and as pendsv is disabled
while in network code, the poll function then just waits there.
When deinit has finished, the poll func is executed, but skipped:
src/cyw43_ctrl.c#L222-L225 this skips the `CYW43_POST_POLL_HOOK` which
would re-enable interrupts, but also reset `cyw43_has_pending`.
And in that state, the lightsleep code, will skip sleeping as it thinks
there is a network packet pending to be handled.
With this change applied, lightsleep works as expected when the wifi chip
is enabled, and when it's powered off.
This renames the builtin-modules, such that help('modules') and printing
the module object will show "module" rather than "umodule".
This work was funded through GitHub Sponsors.
Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This commit prevents the device from "hanging" when using lightsleep while
the WiFi chip is active.
Whenever the WiFi chip wants to interrupt the microcontroller to notify it
for a new package, it sets the CYW43_PIN_WL_HOST_WAKE pin to high,
triggering an IRQ. However, as polling the chip cannot happen in an
interrupt handler, it subsequently notifies the pendsv-service to do a poll
as soon as the interrupt handler ended. In order to prevent a new
interrupt from happening immediately afterwards, even before the poll has
run, the IRQ handler disables interrupts from the pin.
The first problem occurs, when a WiFi package arrives while the main loop
is in cyw43-code. In order to prevent concurrent access of the hardware,
the network code blocks pendsv from running again while entering lwIP code.
The same holds for direct cyw43 code (like changing the cyw43-gpios, i.e.
the LED on the Pico W). While the pendsv is disabled, interrupts can still
occur to schedule a poll (and disable further interrupts), but it will not
run. This can happen while the microcontroller is anywhere in rp2040 code.
In order to preserve power while waiting for cyw43 responses,
cyw43_configport.h defines CYW43_DO_IOCTL_WAIT and
CYW43_SDPCM_SEND_COMMON_WAIT to __WFI(). While this might work in most
cases, there are 2 edge cases where it fails:
- When an interrupt has already been received by the cyw43 stack, for
example due to an incoming ethernet packet.
- When the interrupt from the cyw43 response comes before the
microcontroller entered the __WFI() instruction.
When that happens, wfi will just block forever as no further interrupts are
received. The only way to safely use wfi to wake up from an interrupt is
inside a critical section, as this delays interrupts until the wfi is
entered, possibly resuming immediately until interrupts are reenabled and
the interrupt handler is run. Additionally this critical section needs to
check whether the interrupt has already been disabled and pendsv was
triggered, as in such a case, wfi can never be woken up, and needs to be
skipped, because there is already a package from the network chip waiting.
Note that this turns cyw43_yield into a nop (and thereby the cyw43-loops
into busy waits) from the second time onwards, as after the first call, a
pendsv request will definitely be pending. More logic could be added, to
explicitly enable the interrupt in this case.
Regarding lightsleep, this code has a similar problem. When an interrupt
occurs during lightsleep, the IRQ and pendsv handler and thereby poll are
run immediately, with the clocks still disabled, causing the SPI transfers
to fail. If we don't want to add complex logic inside the IRQ handler we
need to protect the whole lightsleep procedure form interrupts with a
critical section, exiting out early if an interrupt is pending for whatever
reason. Only then we can start to shut down clocks and only enable
interrupts when the system is ready again. Other interrupt handlers might
also be happy, that they are only run when the system is fully operational.
Tested on a Pico W, calling machine.lightsleep() within an endless loop and
pinging from the outside.
This gets basic machine.lightsleep([n]) behaviour working on the rp2 port.
It supports:
- Calling lightsleep without a specified period, in which case it uses xosc
dormant mode. There's currently no way to wake it up from this state,
unless you write to raw registers to enable a GPIO wake up source.
- Calling lightsleep with a period n in milliseconds. This period must be
less than about 72 minutes and uses timer alarm3 to wake it up.
The RTC continues to run during lightsleep, but other peripherals have
their clock turned off during the sleep.
It doesn't yet support longer periods than 72 minutes, or waking up from
GPIO IRQ.
Measured current consumption from the USB port on a PICO board is about
1.5mA when doing machine.lightsleep(5000), and about 0.9mA when doing
machine.lightsleep().
Addresses issue #8770.
Signed-off-by: Damien George <damien@micropython.org>
It's no longer needed because this macro is now processed after
preprocessing the source code via cpp (in the qstr extraction stage), which
means unused MP_REGISTER_MODULE's are filtered out by the preprocessor.
Signed-off-by: Damien George <damien@micropython.org>
This commit adds I2S protocol support for the rp2 port:
- I2S API is consistent with STM32 and ESP32 ports
- I2S configurations supported:
- master transmit and master receive
- 16-bit and 32-bit sample sizes
- mono and stereo formats
- sampling frequency
- 3 modes of operation:
- blocking
- non-blocking with callback
- uasyncio
- internal ring buffer size can be tuned
- DMA IRQs are managed on an I2S object basis, allowing other
RP2 entities to use DMA IRQs when I2S is not being used
- MicroPython documentation
- tested on Raspberry Pi Pico development board
- build metric changes for this commit: text(+4552), data(0), bss(+8)
Signed-off-by: Mike Teachman <mike.teachman@gmail.com>
This commit refactors machine.PWM and creates extmod/machine_pwm.c. The
esp8266, esp32 and rp2 ports all use this and provide implementations of
the required PWM functionality. This helps to reduce code duplication and
keep the same Python API across ports.
This commit does not make any functional changes.
Signed-off-by: Damien George <damien@micropython.org>
Initial support for machine.RTC on rp2 port. It only supports datetime()
method and nothing else. The method gets/returns a tuple of 8 items, just
like esp32 port, for example, but the usec parameter is ignored as the RP2
RTC only works up to seconds precision.
The Pico RTC isn't very useful as the time is lost during reset and there
seems to be no way to easily power up just the RTC clock with a low current
voltage, but still there seems to be use-cases for that, see issues #6831,
and a Thonny issue #1592. It was also requested for inclusion on v1.15
roadmap on #6832.
Signed-off-by: Krzysztof Adamski <k@japko.eu>
When UART is used for REPL and the MCU frequency is changed, the UART
has to be re-initialised. Besides that the UART may have to be recreated
after a frequency change, but with USB REPL this is not a problem.
Thanks to @HermannSW for spotting and providing the change.
Using the standard machine.freq().
The safe ranges tested were 10 and 12-270MHz, at which USB REPL still
worked. Requested settings can be checked with the script:
pico-sdk/src/rp2_common/hardware_clocks/scripts/vcocalc.py. At frequencies
like 300MHz the script still signaled OK, but USB did not work any more.
This commit adds a new port "rp2" which targets the new Raspberry Pi RP2040
microcontroller.
The build system uses pure cmake (with a small Makefile wrapper for
convenience). The USB driver is TinyUSB, and there is a machine module
with most of the standard classes implemented. Some examples are provided
in the examples/rp2/ directory.
Work done in collaboration with Graham Sanderson.
Signed-off-by: Damien George <damien@micropython.org>