Compare commits

...

39 Commits

Author SHA1 Message Date
Amirreza Hamzavi fc15707426
Merge b4d38bea21 into bd21820b4c 2024-01-14 09:47:26 +01:00
stijn bd21820b4c tests/run-tests.py: Fix path-based special test detection.
Compare the full absolute path instead of relying on the path form
passed by the user.

For instance, this will make

python3 run-tests.py -d basics
python3 run-tests.py -d ./basics
python3 run-tests.py -d ../tests/basics
python3 run-tests.py -d /full/path/to/basics

all behave the same by correctly treating the bytes_compare3 and
builtin_help tests as special, whereas previously only the first
invocation would do that and hence result in these tests to fail
when called with a different path form.

Signed-off-by: stijn <stijn@ignitron.net>
2024-01-10 11:34:09 +01:00
stijn 88d21f186b tests/run-tests.py: Make repl test detection more correct.
Avoid unrelated tests which happen to have "repl_" anywhere
in their path to be treated as repl tests.

Signed-off-by: stijn <stijn@ignitron.net>
2024-01-10 11:34:09 +01:00
stijn ba4330ba10 tests/run-tests.py: Remove unneeded argument from run_feature_check().
In 405893af this was likely left as-is to minimize the diff,
but it just complicates things.

Signed-off-by: stijn <stijn@ignitron.net>
2024-01-10 11:34:09 +01:00
Damien George 2ed976f140 samd/mcu/samd21: Enable MICROPY_STACK_CHECK on SAMD21.
Increases firmware size by +140 bytes and uses +4 extra bytes of RAM, but
allows the test suite to run without crashing.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 23:24:39 +11:00
Damien George e456ee40e0 samd/mpconfigport: Simplify and consolidate config options.
This is a no-op in terms of firmware functionality.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 23:24:39 +11:00
Damien George 7ecff515d7 stm32/flash: Fix sector and bank calculation for H5 and H7 MCUs.
Flash sectors should start counting at 0 for each bank.  This commit makes
sure that is the case on all H5 and H7 MCUs, by using `get_page()` instead
of `flash_get_sector_info()`.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 12:35:48 +11:00
Damien George 5cb93f63fb stm32/flash: Factor and simplify erase code.
Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 12:35:22 +11:00
Damien George cd6e0e1022 stm32/flashbdev: Don't rely on flash sector id.
This commit removes the need for a separate `flash_cache_sector_id`
variable, instead using `flash_cache_sector_start` to indicate which sector
is curretly cached (and -1 indicates no sector).

Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 12:34:18 +11:00
Damien George b6ab9e420b stm32/flash: Change flash_erase to only erase a single sector at a time.
An erase sector sits in a given flash bank and some MCUs have two flash
banks.  If trying to erase a range of sectors and that range crosses from
one flash bank into the next, the original implementation of
`flash_erase()` would not handle this case and would do the wrong thing.

This commit changes `flash_erase()` to only erase a single sector, which
sidesteps the need to handle flash-bank-crossing.  Most callers of this
function only need to erase a single sector anyway.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 12:33:34 +11:00
Damien George cf115918e6 stm32/flash: Simplify sector calculation for homogeneous flash layout.
Newer STM32 parts have homogeneous flash layout, and in this case the MCU
configuration and page/sector calculation can be simplified.  The affected
functions are `flash_is_valid_addr()` and `flash_get_sector_info()`, which
are now simpler for homogeneous flash.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 12:31:10 +11:00
Damien George cd0f75069c stm32/flash: Remove commented-out flash functions.
Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 12:31:03 +11:00
Damien George 7002a19be2 stm32/mboot: Improve mass erase to erase all non-protected pages.
Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 12:29:19 +11:00
Damien George b7b99522e4 stm32/mboot: Improve detection of invalid flash erase/write.
This commit replaces the linker symbol `_mboot_writable_flash_start` with
`_mboot_protected_flash_start` and `_mboot_protected_flash_end_exclusive`,
to provide better configuration of the protected flash area.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-08 12:22:55 +11:00
Nicko van Someren 1da45e887a rp2: Provide direct memory access to PIO and SPI FIFOs via proxy arrays.
Signed-off-by: Nicko van Someren <nicko@nicko.org>
2024-01-07 18:27:01 +11:00
Nicko van Someren f8cabe82f7 rp2/rp2_dma: Fix fetching 'write' buffers for writing not reading.
Signed-off-by: Nicko van Someren <nicko@nicko.org>
2024-01-07 18:25:52 +11:00
darc 80fd575c8c embed: Fix alloca include for FreeBSD and NetBSD.
Signed-off-by: darc <darcagn@protonmail.com>
2024-01-05 01:03:25 -06:00
Damien George 42eab32a36 windows/windows_mphal: Fix mp_hal_delay_ms() so it runs events.
This changed behaviour in c393f5c123 when the
MICROPY_EVENT_POLL_HOOK macro was removed.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-05 15:56:34 +11:00
Damien George 0640ff3b97 ports: Move MICROPY_INTERNAL_WFE definition to mphalport.h.
It belongs here because the default value is defined in py/mphal.h.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-05 15:49:42 +11:00
Damien George d45176fc27 ports: Move MICROPY_PY_LWIP_ENTER/REENTER/EXIT defns to mphalport.h.
Following ad806df857 where the
MICROPY_PY_PENDSV_ENTER/REENTER/EXIT macro definitions were moved to
mphalport.h.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-05 15:40:06 +11:00
Damien George ee226a8b43 all: Fix "reuse" and "overridden" spelling mistakes.
Codespell doesn't pick up "re-used" or "re-uses", and ignores the tests/
directory, so fix these manually.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-05 15:08:33 +11:00
Damien George 7a794d0d8e tools/gen-changelog.sh: Exclude "-preview" tags from generated log.
Signed-off-by: Damien George <damien@micropython.org>
2024-01-05 15:06:14 +11:00
stijn 2b56bab226 tests/run-tests.py: Add an option for running only the failed tests.
Implement the typical 're-run the failed tests' most test runners have, for
convenience.  Accessible via the new --run-failures argument, and
implemented using a json file containing a list of the failed tests.

Signed-off-by: stijn <stijn@ignitron.net>
2024-01-05 12:12:57 +11:00
Damien George 0c81ffd31a tests/multi_net: Generate smaller certs with 2048-bit RSA.
Otherwise running the tests can take a long time when the server is a slow
target (RP2040 takes 23 seconds for a handshake when using 4096-bit RSA).

Also add instructions on how to generate elliptic curve key/certs.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-05 11:34:01 +11:00
Damien George f0392b8d3d tests/run-multitests.py: Change to dir of test script when running it.
This matches the behaviour of run-tests.py, which sets cwd to the directory
containing the test script, which helps to isolate the filesystem.

It means that the SSL tests no longer need to know the name of their
containing directory to find the certificate files, and helps to run these
tests on bare-metal.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-05 11:05:34 +11:00
Damien George a003ac2f73 tests/thread: Add a test for accuracy of sleep within a thread.
The existing thread_sleep1.py test only tests execution, not accuracy, of
time.sleep.  Also the existing test only tests sleep(0) on targets like rp2
that can only create a single thread.

The new test in this commit checks for timing accuracy on the main thread
and one other thread when they run at the same time.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-05 10:35:34 +11:00
Damien George 2265d70add tests/thread: Adjust thread tests so most are able to run on rp2 port.
The aim of this commit is to make it so that the existing thread tests can
be used to test the _thread module on the rp2 port.  The rp2 port only
allows up to one thread to be created at a time, and does not have the GIL
enabled.

The following changes have been made:
- run-tests.py skips mutation tests on rp2, because there's no GIL.
- run-tests.py skips other tests on rp2 that require more than one thread.
- The tests stop trying to start a new thread after there is an OSError,
  which indicates that the system cannot create more threads.
- Some of these tests also now run the test function on the main thread,
  not just the spawned threads.
- In some tests the output printing is adjusted so it's the same regardless
  of how many threads were spawned.
- Some time.sleep(1) are replaced with time.sleep(0) to make the tests run
  a little faster (finish sooner when the work is done).

For the most part the tests are unchanged for existing platforms like esp32
and unix.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-05 10:02:27 +11:00
Damien George 231fc20ce0 tests/run-tests.py: Remove machine_mem.py test from skip list.
This test was removed long ago in eb0e3bab1e.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-04 14:53:11 +11:00
Damien George dc2a4e3cbd rp2/mpthreadport: Fix race with IRQ when entering atomic section.
Prior to this commit there is a potential deadlock in
mp_thread_begin_atomic_section(), when obtaining the atomic_mutex, in the
following situation:
- main thread calls mp_thread_begin_atomic_section() (for whatever reason,
  doesn't matter)
- the second core is running so the main thread grabs the mutex via the
  call mp_thread_mutex_lock(&atomic_mutex, 1), and this succeeds
- before the main thread has a chance to run save_and_disable_interrupts()
  a USB IRQ comes in and the main thread jumps off to process this IRQ
- that USB processing triggers a call to the dcd_event_handler() wrapper
  from commit bcbdee2357
- that then calls mp_sched_schedule_node()
- that then attempts to obtain the atomic section, calling
  mp_thread_begin_atomic_section()
- that call then blocks trying to obtain atomic_mutex
- core0 is now deadlocked on itself, because the main thread has the mutex
  but the IRQ handler (which preempted the main thread) is blocked waiting
  for the mutex, which will never be free

The solution in this commit is to use mutex enter/exit functions that also
atomically disable/restore interrupts.

Fixes issues #12980 and #13288.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-03 15:59:11 +11:00
Damien George 8438c8790c rp2/mutex_extra: Implement additional mutex functions.
These allow entering/exiting a mutex and also disabling/restoring
interrupts, in an atomic way.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-03 15:59:02 +11:00
Damien George c3989e398f rp2/rp2_flash: Lockout second core only when doing flash erase/write.
Using the multicore lockout feature in the general atomic section makes it
much more difficult to get correct.

Signed-off-by: Damien George <damien@micropython.org>
2024-01-03 15:58:39 +11:00
robert-hh 3d0b6276f3 samd/mcu: Fix wrong EIC table entries in pin-af-table.csv.
Fixes:
- SAMD21: PB16
- SAMD51: PB03, PB22 and PB00.

Signed-off-by: robert-hh <robert@hammelrath.com>
2024-01-02 18:48:17 +11:00
robert-hh aea93a88f8 samd/mcu/samd21: Reorganize and enable more firmware features.
This commit enables additional features for SAMD21 with external flash:
- Viper and native code support.  On a relatively slow devices, viper and
  native code can be helpful.
- Freeze the asyncio scripts and add the select module.
- Enable Framebuffer support.
- Enable UART flow control.
- Enable a few more features from the extra features set.

Drop onewire and asyncio support from SAMD21 firmware without external
flash, leaving a little bit more room for future extensions.  Asyncio was
anyhow incomplete.

Signed-off-by: robert-hh <robert@hammelrath.com>
2024-01-02 18:46:33 +11:00
robert-hh 36d9e98fc6 samd: Remove the MICROPY_PY_MACHINE_RTC config option.
RTC is enabled on all boards.  Therefore the conditional compile is not
needed.  Removing it simplifies the source code a little bit.

Signed-off-by: robert-hh <robert@hammelrath.com>
2024-01-02 18:46:11 +11:00
robert-hh 8498b0b13e docs/samd/pinout: Update pinout docs with fixed pin assignment.
Fixes a wrong assignment for Sparkfun SAMD51 Thing Plus, and updates the
sample script for printing the pin info table.

Signed-off-by: robert-hh <robert@hammelrath.com>
2024-01-02 18:44:45 +11:00
iabdalkader f34e27f178 mimxrt/mpbthciport: Add missing extmod/modmachine.h header.
Include extmod/modmachine.h for machine_uart_type declaration.

Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
2024-01-02 18:24:19 +11:00
iabdalkader 87d3f8b367 mimxrt/mphalport: Remove redundant NVIC/IRQ defines.
These are already defined in `irq.h`.

Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
2024-01-02 18:19:58 +11:00
Damien George 2037edb5a2 all: Bump version to 1.23.0-preview.
Signed-off-by: Damien George <damien@micropython.org>
2024-01-02 18:11:41 +11:00
Amirreza Hamzavi b4d38bea21 docs/library/machine: Add docs for RTC.memory() method.
Co-Authored-By: glenn20 <glenn20@users.noreply.github.com>
Signed-off-by: Amirreza Hamzavi <amirrezahamzavi2000@gmail.com>
2023-10-13 14:46:51 +03:30
81 changed files with 736 additions and 523 deletions

View File

@ -69,6 +69,8 @@ used during the build process and is not part of the compiled source code.
/FreeRTOS (GPL-2.0 with FreeRTOS exception)
/esp32
/ppp_set_auth.* (Apache-2.0)
/rp2
/mutex_extra.c (BSD-3-clause)
/stm32
/usbd*.c (MCD-ST Liberty SW License Agreement V2)
/stm32_it.* (MIT + BSD-3-clause)

View File

@ -312,7 +312,7 @@ Broadcaster Role (Advertiser)
in all broadcasts, and *resp_data* is send in reply to an active scan.
**Note:** if *adv_data* (or *resp_data*) is ``None``, then the data passed
to the previous call to ``gap_advertise`` will be re-used. This allows a
to the previous call to ``gap_advertise`` will be reused. This allows a
broadcaster to resume advertising with just ``gap_advertise(interval_us)``.
To clear the advertising payload pass an empty ``bytes``, i.e. ``b''``.

View File

@ -75,6 +75,17 @@ Methods
- ``wake`` specifies the sleep mode from where this interrupt can wake
up the system.
.. method:: RTC.memory([data])
Data written to RTC user memory is persistent across restarts, including
`machine.soft_reset()` and `machine.deepsleep()`. ``RTC.memory(data)``
will write ``data`` to the RTC memory, where ``data`` is any object which
supports the buffer protocol (including `bytes`, `bytearray`, `memoryview`
and `array.array`). `RTC.memory()` reads RTC memory and returns a `bytes`
object. The maximum length of RTC user memory is 2048 bytes by default.
Availability: ESP32, ESP8266.
Constants
---------

View File

@ -32,7 +32,7 @@ Methods
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.
reused 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.

View File

@ -211,7 +211,7 @@ two loops:
spi.readinto(buf)
# process data in buf
The first creates a buffer on each pass whereas the second re-uses a pre-allocated
The first creates a buffer on each pass whereas the second reuses a pre-allocated
buffer; this is both faster and more efficient in terms of memory fragmentation.
**Bytes are smaller than ints**

View File

@ -870,7 +870,7 @@ Adafruit ItsyBitsy M4 Express :ref:`samd51_pinout_table`.
The default devices at the board are:
- UART 1 at pins PB23/PB22, labelled RXD/TXD
- UART 2 at pins PA13/PA12, labelled RXD/TXD
- I2C 5 at pins PA22/PA23, labelled SDA/SCL
- SPI 4 at pins PB12/PB11/PB13, labelled MOSI, MISO and SCK
- DAC output on pins PA02 and PA05, labelled A0 and A4
@ -884,36 +884,36 @@ The tables shown above were created with small a Python script running on the ta
from machine import Pin
import os
def print_entry(e, txt):
def print_item(e, txt):
print(txt, end=": ")
if e == 255:
print(" - ", end="")
else:
print("%d/%d" % (e >> 4, e & 0x0f), end="")
def print_pininfo(pin, info):
print("%3d" % pin, end=" ")
print("P%c%02d" % ("ABCD"[pin // 32], pin % 32), end="")
print(" %12s" % info[0], end="")
def print_pininfo(pin_id, name, info):
print("%3d" % pin_id, end=" ")
print("%4s %12s" % (info[0], name), end="")
print(" IRQ:%2s" % (info[1] if info[1] != 255 else "-"), end="")
print(" ADC0:%2s" % (info[2] if info[2] != 255 else "-"), end="")
if len(info) == 7:
print_entry(info[3], " Serial1")
print_entry(info[4], " Serial2")
print_entry(info[5], " PWM1" if (info[5] >> 4) < 3 else " TC")
print_entry(info[6], " PWM2")
print_item(info[3], " Serial1")
print_item(info[4], " Serial2")
print_item(info[5], " PWM1" if (info[5] >> 4) < 3 else " TC")
print_item(info[6], " PWM2")
else:
print(" ADC1:%2s" % (info[3] if info[3] != 255 else "-"), end="")
print_entry(info[4], " Serial1")
print_entry(info[5], " Serial2")
print_entry(info[6], " TC")
print_entry(info[7], " PWM1")
print_entry(info[8], " PWM2")
print_item(info[4], " Serial1")
print_item(info[5], " Serial2")
print_item(info[6], " TC")
print_item(info[7], " PWM1")
print_item(info[8], " PWM2")
print()
def tblkey(i):
name = i[1][0]
if name != "-":
name = i[1]
if name != "":
if len(name) < 3:
return " " + name
else:
@ -921,17 +921,25 @@ The tables shown above were created with small a Python script running on the ta
else:
return "zzzzzzz%03d" % i[0]
def table(num = 127):
def table(num=127, sort=True):
pintbl = []
inv_bd = {v: k for k, v in Pin.board.__dict__.items()}
for i in range(num):
try:
pintbl.append((i, pininfo(i)))
p = Pin(i)
pi = pininfo(p)
if p in inv_bd.keys():
name = inv_bd[p]
else:
name = ""
pintbl.append((i, name, pininfo(i)))
except:
pass
# print("not defined")
pintbl.sort(key=tblkey)
if sort:
pintbl.sort(key=tblkey)
for item in pintbl:
print_pininfo(item[0], item[1])
print_pininfo(item[0], item[1], item[2])
table()

View File

@ -33,6 +33,10 @@ typedef uintptr_t mp_uint_t; // must be pointer size
typedef long mp_off_t;
// Need to provide a declaration/definition of alloca()
#if defined(__FreeBSD__) || defined(__NetBSD__)
#include <stdlib.h>
#else
#include <alloca.h>
#endif
#define MICROPY_MPHALPORT_H "port/mphalport.h"

View File

@ -29,6 +29,7 @@
#include "py/stream.h"
#include "py/mphal.h"
#include "extmod/modbluetooth.h"
#include "extmod/modmachine.h"
#include "extmod/mpbthci.h"
#include "shared/runtime/softtimer.h"
#include "modmachine.h"

View File

@ -134,11 +134,6 @@ uint32_t trng_random_u32(void);
#define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL)
// #define MICROPY_PY_CRYPTOLIB (MICROPY_PY_SSL)
// Prevent the "LWIP task" from running.
#define MICROPY_PY_LWIP_ENTER MICROPY_PY_PENDSV_ENTER
#define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER
#define MICROPY_PY_LWIP_EXIT MICROPY_PY_PENDSV_EXIT
#ifndef MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1)
#endif

View File

@ -41,13 +41,15 @@
// For regular code that wants to prevent "background tasks" from running.
// These background tasks (LWIP, Bluetooth) run in PENDSV context.
// TODO: Check for the settings of the STM32 port in irq.h
#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003)
#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
#define MICROPY_PY_PENDSV_ENTER uint32_t atomic_state = raise_irq_pri(IRQ_PRI_PENDSV);
#define MICROPY_PY_PENDSV_REENTER atomic_state = raise_irq_pri(IRQ_PRI_PENDSV);
#define MICROPY_PY_PENDSV_EXIT restore_irq_pri(atomic_state);
// Prevent the "lwIP task" from running.
#define MICROPY_PY_LWIP_ENTER MICROPY_PY_PENDSV_ENTER
#define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER
#define MICROPY_PY_LWIP_EXIT MICROPY_PY_PENDSV_EXIT
#define MICROPY_HW_USB_CDC_TX_TIMEOUT (500)
#define MP_HAL_PIN_FMT "%q"

View File

@ -292,10 +292,6 @@ typedef long mp_off_t;
#define MICROPY_THREAD_YIELD()
#endif
#define MICROPY_PY_LWIP_ENTER
#define MICROPY_PY_LWIP_REENTER
#define MICROPY_PY_LWIP_EXIT
#ifndef MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1)
#endif

View File

@ -35,6 +35,10 @@
#define MICROPY_PY_PENDSV_ENTER uint32_t atomic_state = raise_irq_pri(IRQ_PRI_PENDSV)
#define MICROPY_PY_PENDSV_EXIT restore_irq_pri(atomic_state)
#define MICROPY_PY_LWIP_ENTER
#define MICROPY_PY_LWIP_REENTER
#define MICROPY_PY_LWIP_EXIT
#define MICROPY_HW_USB_CDC_TX_TIMEOUT (500)
extern const unsigned char mp_hal_status_to_errno_table[4];

View File

@ -129,6 +129,7 @@ set(MICROPY_SOURCE_PORT
mphalport.c
mpnetworkport.c
mpthreadport.c
mutex_extra.c
pendsv.c
rp2_flash.c
rp2_pio.c

View File

@ -302,6 +302,18 @@ STATIC void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8
}
}
// Buffer protocol implementation for SPI.
// The buffer represents the SPI data FIFO.
STATIC mp_int_t machine_spi_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
machine_spi_obj_t *self = MP_OBJ_TO_PTR(o_in);
bufinfo->len = 4;
bufinfo->typecode = 'I';
bufinfo->buf = (void *)&spi_get_hw(self->spi_inst)->dr;
return 0;
}
STATIC const mp_machine_spi_p_t machine_spi_p = {
.init = machine_spi_init,
.transfer = machine_spi_transfer,
@ -314,6 +326,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
make_new, machine_spi_make_new,
print, machine_spi_print,
protocol, &machine_spi_p,
buffer, machine_spi_get_buffer,
locals_dict, &mp_machine_spi_locals_dict
);

View File

@ -245,24 +245,6 @@ extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k;
#define MICROPY_HW_BOOTSEL_DELAY_US 8
#endif
// Prevent the "lwIP task" from running when unsafe to do so.
#define MICROPY_PY_LWIP_ENTER lwip_lock_acquire();
#define MICROPY_PY_LWIP_REENTER lwip_lock_acquire();
#define MICROPY_PY_LWIP_EXIT lwip_lock_release();
// Port level Wait-for-Event macro
//
// Do not use this macro directly, include py/runtime.h and
// call mp_event_wait_indefinite() or mp_event_wait_ms(timeout)
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) \
do { \
if ((TIMEOUT_MS) < 0) { \
__wfe(); \
} else { \
best_effort_wfe_or_timeout(make_timeout_time_ms(TIMEOUT_MS)); \
} \
} while (0)
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1))
#define MP_SSIZE_MAX (0x7fffffff)

View File

@ -43,6 +43,24 @@
#define MICROPY_PY_PENDSV_ENTER pendsv_suspend()
#define MICROPY_PY_PENDSV_EXIT pendsv_resume()
// Prevent the "lwIP task" from running when unsafe to do so.
#define MICROPY_PY_LWIP_ENTER lwip_lock_acquire();
#define MICROPY_PY_LWIP_REENTER lwip_lock_acquire();
#define MICROPY_PY_LWIP_EXIT lwip_lock_release();
// Port level Wait-for-Event macro
//
// Do not use this macro directly, include py/runtime.h and
// call mp_event_wait_indefinite() or mp_event_wait_ms(timeout)
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) \
do { \
if ((TIMEOUT_MS) < 0) { \
__wfe(); \
} else { \
best_effort_wfe_or_timeout(make_timeout_time_ms(TIMEOUT_MS)); \
} \
} while (0)
extern int mp_interrupt_char;
extern ringbuf_t stdin_ringbuf;

View File

@ -30,6 +30,7 @@
#include "py/mpthread.h"
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "mutex_extra.h"
#if MICROPY_PY_THREAD
@ -45,27 +46,23 @@ STATIC uint32_t *core1_stack = NULL;
STATIC size_t core1_stack_num_words = 0;
// Thread mutex.
STATIC mp_thread_mutex_t atomic_mutex;
STATIC mutex_t atomic_mutex;
uint32_t mp_thread_begin_atomic_section(void) {
if (core1_entry) {
// When both cores are executing, we also need to provide
// full mutual exclusion.
mp_thread_mutex_lock(&atomic_mutex, 1);
// In case this atomic section is for flash access, then
// suspend the other core.
multicore_lockout_start_blocking();
return mutex_enter_blocking_and_disable_interrupts(&atomic_mutex);
} else {
return save_and_disable_interrupts();
}
return save_and_disable_interrupts();
}
void mp_thread_end_atomic_section(uint32_t state) {
restore_interrupts(state);
if (core1_entry) {
multicore_lockout_end_blocking();
mp_thread_mutex_unlock(&atomic_mutex);
if (atomic_mutex.owner != LOCK_INVALID_OWNER_ID) {
mutex_exit_and_restore_interrupts(&atomic_mutex, state);
} else {
restore_interrupts(state);
}
}
@ -73,7 +70,7 @@ void mp_thread_end_atomic_section(uint32_t state) {
void mp_thread_init(void) {
assert(get_core_num() == 0);
mp_thread_mutex_init(&atomic_mutex);
mutex_init(&atomic_mutex);
// Allow MICROPY_BEGIN_ATOMIC_SECTION to be invoked from core1.
multicore_lockout_victim_init();

30
ports/rp2/mutex_extra.c Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "mutex_extra.h"
// These functions are taken from lib/pico-sdk/src/common/pico_sync/mutex.c and modified
// so that they atomically obtain the mutex and disable interrupts.
uint32_t __time_critical_func(mutex_enter_blocking_and_disable_interrupts)(mutex_t * mtx) {
lock_owner_id_t caller = lock_get_caller_owner_id();
do {
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
if (!lock_is_owner_id_valid(mtx->owner)) {
mtx->owner = caller;
spin_unlock_unsafe(mtx->core.spin_lock);
return save;
}
lock_internal_spin_unlock_with_wait(&mtx->core, save);
} while (true);
}
void __time_critical_func(mutex_exit_and_restore_interrupts)(mutex_t * mtx, uint32_t save) {
spin_lock_unsafe_blocking(mtx->core.spin_lock);
assert(lock_is_owner_id_valid(mtx->owner));
mtx->owner = LOCK_INVALID_OWNER_ID;
lock_internal_spin_unlock_with_notify(&mtx->core, save);
}

34
ports/rp2/mutex_extra.h Normal file
View File

@ -0,0 +1,34 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_RP2_MUTEX_EXTRA_H
#define MICROPY_INCLUDED_RP2_MUTEX_EXTRA_H
#include "pico/mutex.h"
uint32_t mutex_enter_blocking_and_disable_interrupts(mutex_t *mtx);
void mutex_exit_and_restore_interrupts(mutex_t *mtx, uint32_t save);
#endif // MICROPY_INCLUDED_RP2_MUTEX_EXTRA_H

View File

@ -86,7 +86,7 @@ STATIC const uint32_t rp2_dma_ctrl_field_count = MP_ARRAY_SIZE(rp2_dma_ctrl_fiel
STATIC uint32_t rp2_dma_register_value_from_obj(mp_obj_t o, int reg_type) {
if (reg_type == REG_TYPE_ADDR_READ || reg_type == REG_TYPE_ADDR_WRITE) {
mp_buffer_info_t buf_info;
mp_uint_t flags = MP_BUFFER_READ;
mp_uint_t flags = (reg_type == REG_TYPE_ADDR_READ) ? MP_BUFFER_READ : MP_BUFFER_WRITE;
if (mp_get_buffer(o, &buf_info, flags)) {
return (uint32_t)buf_info.buf;
}

View File

@ -70,6 +70,22 @@ bi_decl(bi_block_device(
BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN));
// Flash erase and write must run with interrupts disabled and the other core suspended,
// because the XIP bit gets disabled.
static uint32_t begin_critical_flash_section(void) {
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
multicore_lockout_start_blocking();
}
return save_and_disable_interrupts();
}
static void end_critical_flash_section(uint32_t state) {
restore_interrupts(state);
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
multicore_lockout_end_blocking();
}
}
STATIC mp_obj_t rp2_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
// Parse arguments
enum { ARG_start, ARG_len };
@ -135,19 +151,17 @@ STATIC mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
if (n_args == 3) {
// Flash erase/program must run in an atomic section because the XIP bit gets disabled.
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
mp_uint_t atomic_state = begin_critical_flash_section();
flash_range_erase(self->flash_base + offset, bufinfo.len);
MICROPY_END_ATOMIC_SECTION(atomic_state);
end_critical_flash_section(atomic_state);
mp_event_handle_nowait();
// TODO check return value
} else {
offset += mp_obj_get_int(args[3]);
}
// Flash erase/program must run in an atomic section because the XIP bit gets disabled.
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
mp_uint_t atomic_state = begin_critical_flash_section();
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
MICROPY_END_ATOMIC_SECTION(atomic_state);
end_critical_flash_section(atomic_state);
mp_event_handle_nowait();
// TODO check return value
return mp_const_none;
@ -170,10 +184,9 @@ STATIC mp_obj_t rp2_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_
return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES);
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
uint32_t offset = mp_obj_get_int(arg_in) * BLOCK_SIZE_BYTES;
// Flash erase/program must run in an atomic section because the XIP bit gets disabled.
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
mp_uint_t atomic_state = begin_critical_flash_section();
flash_range_erase(self->flash_base + offset, BLOCK_SIZE_BYTES);
MICROPY_END_ATOMIC_SECTION(atomic_state);
end_critical_flash_section(atomic_state);
// TODO check return value
return MP_OBJ_NEW_SMALL_INT(0);
}

View File

@ -809,6 +809,23 @@ STATIC mp_obj_t rp2_state_machine_tx_fifo(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(rp2_state_machine_tx_fifo_obj, rp2_state_machine_tx_fifo);
// Buffer protocol implementation for StateMachine.
// The buffer represents one of the FIFO ports of the state machine. Note that a different
// pointer is returned depending on if this is for reading or writing.
STATIC mp_int_t rp2_state_machine_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
rp2_state_machine_obj_t *self = MP_OBJ_TO_PTR(o_in);
bufinfo->len = 4;
bufinfo->typecode = 'I';
if (flags & MP_BUFFER_WRITE) {
bufinfo->buf = (void *)&self->pio->txf[self->sm];
} else {
bufinfo->buf = (void *)&self->pio->rxf[self->sm];
}
return 0;
}
// StateMachine.irq(handler=None, trigger=0|1, hard=False)
STATIC mp_obj_t rp2_state_machine_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_handler, ARG_trigger, ARG_hard };
@ -884,6 +901,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
MP_TYPE_FLAG_NONE,
make_new, rp2_state_machine_make_new,
print, rp2_state_machine_print,
buffer, rp2_state_machine_get_buffer,
locals_dict, &rp2_state_machine_locals_dict
);

View File

@ -68,7 +68,8 @@ CFLAGS += $(INC) -Wall -Werror -std=c99 -nostdlib -mthumb $(CFLAGS_MCU) -fsingle
CFLAGS += -DMCU_$(MCU_SERIES) -D__$(CMSIS_MCU)__
CFLAGS += $(CFLAGS_EXTRA)
CFLAGS += -DMICROPY_HW_CODESIZE=$(MICROPY_HW_CODESIZE)
# Strip the letter 'K' from MICROPY_HW_CODESIZE for use by C code.
CFLAGS += -DMICROPY_HW_CODESIZE=$(strip $(subst K,' ', $(MICROPY_HW_CODESIZE)))
LDFLAGS += -nostdlib $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref
LDFLAGS += --defsym=_codesize=$(MICROPY_HW_CODESIZE)

View File

@ -33,13 +33,5 @@
extern uint32_t time_offset;
MP_WEAK DWORD get_fattime(void) {
#if MICROPY_PY_MACHINE_RTC
return (RTC->MODE2.CLOCK.reg >> 1) + (20 << 25);
#else
extern void rtc_gettime(timeutils_struct_time_t *tm);
timeutils_struct_time_t tm;
timeutils_seconds_since_epoch_to_struct_time(mp_hal_ticks_ms_64() / 1000 + time_offset, &tm);
return ((tm.tm_year - 1980) << 25) | ((tm.tm_mon) << 21) | ((tm.tm_mday) << 16) |
((tm.tm_hour) << 11) | ((tm.tm_min) << 5) | (tm.tm_sec / 2);
#endif
}

View File

@ -31,8 +31,6 @@
#include "extmod/modmachine.h"
#include "sam.h"
#if MICROPY_PY_MACHINE_RTC
typedef struct _machine_rtc_obj_t {
mp_obj_base_t base;
mp_obj_t callback;
@ -177,5 +175,3 @@ MP_DEFINE_CONST_OBJ_TYPE(
make_new, machine_rtc_make_new,
locals_dict, &machine_rtc_locals_dict
);
#endif // MICROPY_PY_MACHINE_RTC

View File

@ -0,0 +1,5 @@
include("$(PORT_DIR)/boards/manifest.py")
include("$(MPY_DIR)/extmod/asyncio")
require("onewire")
require("ds18x20")
require("dht")

View File

@ -1,41 +1,80 @@
// Deinitions common to all SAMD21 boards
#include "samd21.h"
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES)
#if MICROPY_HW_CODESIZE == 248
#define SAMD21_EXTRA_FEATURES 1
#else
#define SAMD21_EXTRA_FEATURES 0
#endif
// MicroPython emitters
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_EMIT_THUMB (SAMD21_EXTRA_FEATURES)
#define MICROPY_EMIT_INLINE_THUMB (SAMD21_EXTRA_FEATURES)
#define MICROPY_EMIT_THUMB_ARMV7M (0)
#define MICROPY_MODULE_BUILTIN_INIT (1)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#ifndef MICROPY_PY_BUILTINS_COMPLEX
#define MICROPY_PY_BUILTINS_COMPLEX (0)
#endif
#ifndef MICROPY_PY_TIME
#define MICROPY_PY_TIME (1)
#endif
#ifndef MICROPY_PY_MATH
#define MICROPY_PY_MATH (1)
#endif
#ifndef MICROPY_PY_CMATH
#define MICROPY_PY_CMATH (0)
#endif
// Selected extensions beyond the basic features set.
#define MICROPY_ENABLE_FINALISER (1)
#define MICROPY_STACK_CHECK (1)
#define MICROPY_KBD_EXCEPTION (1)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_REPL_AUTO_INDENT (1)
#define MICROPY_ENABLE_SOURCE_LINE (1)
#define MICROPY_STREAMS_NON_BLOCK (1)
#define MICROPY_PY_BUILTINS_HELP (1)
#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
#define MICROPY_ENABLE_SCHEDULER (1)
#define MICROPY_PY_BUILTINS_BYTES_HEX (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BUILTINS_INPUT (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_SYS_STDFILES (1)
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_IO_IOBASE (1)
#define MICROPY_PY_OS (1)
#define MICROPY_PY_JSON (1)
#define MICROPY_PY_RE (1)
#define MICROPY_PY_BINASCII (1)
#define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_HEAPQ (1)
#define MICROPY_PY_RANDOM (1)
#define MICROPY_PY_PLATFORM (1)
#define MICROPY_PY_RANDOM_SEED_INIT_FUNC (trng_random_u32(300))
unsigned long trng_random_u32(int delay);
#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages;
#ifndef MICROPY_HW_UART_TXBUF
#define MICROPY_HW_UART_TXBUF (1)
#endif
#ifndef MICROPY_HW_UART_RTSCTS
#define MICROPY_HW_UART_RTSCTS (SAMD21_EXTRA_FEATURES)
#endif
// selected extensions of the extra features set
#define MICROPY_PY_OS_URANDOM (1)
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (SAMD21_EXTRA_FEATURES)
#define MICROPY_COMP_RETURN_IF_EXPR (SAMD21_EXTRA_FEATURES)
#define MICROPY_OPT_MPZ_BITWISE (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_BUILTINS_STR_CENTER (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_BUILTINS_STR_PARTITION (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_BUILTINS_ROUND_INT (SAMD21_EXTRA_FEATURES)
#define MICROPY_CAN_OVERRIDE_BUILTINS (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_SYS_STDIO_BUFFER (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_FRAMEBUF (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_ASYNCIO (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_SELECT (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_ERRNO (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_DEFLATE (SAMD21_EXTRA_FEATURES)
#define MICROPY_PY_ONEWIRE (SAMD21_EXTRA_FEATURES)
#ifndef MICROPY_PY_MACHINE_PIN_BOARD_CPU
#define MICROPY_PY_MACHINE_PIN_BOARD_CPU (1)
#endif
#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages;
#define CPU_FREQ (48000000)
#define DFLL48M_FREQ (48000000)

View File

@ -6,6 +6,10 @@ MPY_CROSS_MCU_ARCH = armv6m
MICROPY_HW_CODESIZE ?= 184K
ifeq ($(MICROPY_HW_CODESIZE), 248K)
FROZEN_MANIFEST ?= mcu/$(MCU_SERIES_LOWER)/manifest.py
endif
MICROPY_VFS_LFS1 ?= 1
SRC_S += shared/runtime/gchelper_thumb1.s

View File

@ -42,7 +42,7 @@ PA16,0,,10,30,20,06
PA17,1,,11,31,21,07
PA18,2,,12,32,30,02
PA19,3,,13,33,31,03
PB16,9,,50,,60,04
PB16,0,,50,,60,04
PB17,1,,51,,61,05
PA20,4,,52,32,70,04
PA21,5,,53,33,71,07

1 # The pin_cap_tables contain the information anbout pin mux set and pad
42 PA17,1,,11,31,21,07
43 PA18,2,,12,32,30,02
44 PA19,3,,13,33,31,03
45 PB16,9,,50,,60,04 PB16,0,,50,,60,04
46 PB17,1,,51,,61,05
47 PA20,4,,52,32,70,04
48 PA21,5,,53,33,71,07

View File

@ -10,23 +10,9 @@
// Python internal features
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#ifndef MICROPY_PY_BUILTINS_COMPLEX
#define MICROPY_PY_BUILTINS_COMPLEX (0)
#endif
#ifndef MICROPY_PY_MATH
#define MICROPY_PY_MATH (1)
#define MP_NEED_LOG2 (1)
#endif
#ifndef MICROPY_PY_CMATH
#define MICROPY_PY_CMATH (0)
#endif
#define MICROPY_PY_OS_SYNC (1)
#define MICROPY_PY_OS_URANDOM (1)
#define MICROPY_PY_ONEWIRE (1)
#define MICROPY_PY_RANDOM_SEED_INIT_FUNC (trng_random_u32())
unsigned long trng_random_u32(void);

View File

@ -11,7 +11,7 @@
# Rows not starting with pa, pb, pc or pd are ignored.
# When editing the table with a spread sheet, take care to import the data as text.
Pin,EIC,ADC0,ADC1,SERCOM1,SERCOM2,TC,TCC1,TCC2
PB03,9,15,,,51,61,,
PB03,3,15,,,51,61,,
PA00,0,,,,10,20,,
PA01,1,,,,11,21,,
PC00,0,,10,,,,,
@ -87,7 +87,7 @@ PA22,6,,,30,51,40,16,02
PA23,7,,,31,50,41,17,03
PA24,8,,,32,52,50,22,
PA25,9,,,33,53,51,,
PB22,22,,,12,52,70,,
PB22,6,,,12,52,70,,
PB23,7,,,13,53,71,,
PB24,8,,,00,21,,,
PB25,9,,,01,20,,,
@ -107,6 +107,6 @@ PB30,14,,,70,51,00,40,06
PB31,15,,,71,50,01,41,07
PC30,14,,12,,,,,
PC31,15,,13,,,,,
PB00,9,12,,,52,70,,
PB00,0,12,,,52,70,,
PB01,1,13,,,53,71,,
PB02,2,14,,,50,60,22,

1 # The pin_cap_table is a subset from table 6-1 of the data sheet.
11 # Rows not starting with pa, pb, pc or pd are ignored.
12 # When editing the table with a spread sheet, take care to import the data as text.
13 Pin,EIC,ADC0,ADC1,SERCOM1,SERCOM2,TC,TCC1,TCC2
14 PB03,9,15,,,51,61,, PB03,3,15,,,51,61,,
15 PA00,0,,,,10,20,,
16 PA01,1,,,,11,21,,
17 PC00,0,,10,,,,,
87 PA23,7,,,31,50,41,17,03
88 PA24,8,,,32,52,50,22,
89 PA25,9,,,33,53,51,,
90 PB22,22,,,12,52,70,, PB22,6,,,12,52,70,,
91 PB23,7,,,13,53,71,,
92 PB24,8,,,00,21,,,
93 PB25,9,,,01,20,,,
107 PB31,15,,,71,50,01,41,07
108 PC30,14,,12,,,,,
109 PC31,15,,13,,,,,
110 PB00,9,12,,,52,70,, PB00,0,12,,,52,70,,
111 PB01,1,13,,,53,71,,
112 PB02,2,14,,,50,60,22,

View File

@ -48,16 +48,10 @@
#define LIGHTSLEEP_CPU_FREQ 200000
#if MICROPY_PY_MACHINE_RTC
#define MICROPY_PY_MACHINE_RTC_ENTRY { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) },
#else
#define MICROPY_PY_MACHINE_RTC_ENTRY
#endif
#define MICROPY_PY_MACHINE_EXTRA_GLOBALS \
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, \
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, \
MICROPY_PY_MACHINE_RTC_ENTRY \
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, \
\
/* Class constants. */ \
/* Use numerical constants instead of the symbolic names, */ \

View File

@ -40,25 +40,18 @@
// MicroPython emitters
#define MICROPY_PERSISTENT_CODE_LOAD (1)
// Compiler configuration
#define MICROPY_COMP_CONST (1)
// Python internal features
#define MICROPY_ENABLE_GC (1)
#define MICROPY_ENABLE_FINALISER (1)
#define MICROPY_KBD_EXCEPTION (1)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_REPL_AUTO_INDENT (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_ENABLE_SOURCE_LINE (1)
#define MICROPY_STREAMS_NON_BLOCK (1)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#ifndef MICROPY_PY_BUILTINS_COMPLEX
#define MICROPY_PY_BUILTINS_COMPLEX (0)
#endif
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_PY_BUILTINS_HELP (1)
#define MICROPY_PY_BUILTINS_HELP_TEXT samd_help_text
#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
#define MICROPY_USE_INTERNAL_ERRNO (1)
#define MICROPY_ENABLE_SCHEDULER (1)
#define MICROPY_SCHEDULER_STATIC_NODES (1)
#define MICROPY_HW_ENABLE_USBDEV (1)
#define MICROPY_HW_USB_CDC_1200BPS_TOUCH (1)
@ -71,22 +64,9 @@
#ifndef MICROPY_HW_USB_DESC_STR_MAX
#define MICROPY_HW_USB_DESC_STR_MAX (32)
#endif
#endif
// Control over Python builtins
#define MICROPY_PY_BUILTINS_BYTES_HEX (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BUILTINS_INPUT (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_SYS (1)
#define MICROPY_PY_SYS_PLATFORM "samd"
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_STDFILES (1)
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_IO (1)
#define MICROPY_PY_IO_IOBASE (1)
// Extended modules
#define MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME (1)
@ -97,19 +77,9 @@
#define MICROPY_PY_MACHINE_BARE_METAL_FUNCS (1)
#define MICROPY_PY_MACHINE_BOOTLOADER (1)
#define MICROPY_PY_MACHINE_DISABLE_IRQ_ENABLE_IRQ (1)
#define MICROPY_PY_OS (1)
#define MICROPY_PY_OS_INCLUDEFILE "ports/samd/modos.c"
#define MICROPY_READER_VFS (1)
#define MICROPY_VFS (1)
#define MICROPY_PY_JSON (1)
#define MICROPY_PY_RE (1)
#define MICROPY_PY_BINASCII (1)
#define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_HEAPQ (1)
#define MICROPY_PY_RANDOM (1)
#define MICROPY_PY_DEFLATE (1)
#define MICROPY_PY_ASYNCIO (1)
#define MICROPY_PY_MACHINE_RTC (1)
#ifndef MICROPY_PY_MACHINE_ADC
#define MICROPY_PY_MACHINE_ADC (1)
#endif
@ -151,8 +121,6 @@
#define MICROPY_PY_MACHINE_WDT (1)
#define MICROPY_PY_MACHINE_WDT_INCLUDEFILE "ports/samd/machine_wdt.c"
#define MICROPY_PY_MACHINE_WDT_TIMEOUT_MS (1)
#define MICROPY_PY_ONEWIRE (1)
#define MICROPY_PY_PLATFORM (1)
#define MICROPY_PLATFORM_VERSION "ASF4"
#define MP_STATE_PORT MP_STATE_VM
@ -192,5 +160,8 @@ typedef int mp_int_t; // must be pointer size
typedef unsigned mp_uint_t; // must be pointer size
typedef long mp_off_t;
// Need an implementation of the log2 function which is not a macro.
#define MP_NEED_LOG2 (1)
// Need to provide a declaration/definition of alloca()
#include <alloca.h>

View File

@ -38,9 +38,7 @@
#include "tusb.h"
#include "mphalport.h"
#if MICROPY_PY_MACHINE_RTC
extern void machine_rtc_start(bool force);
#endif
static void usb_init(void) {
// Init USB clock
@ -124,9 +122,7 @@ void samd_init(void) {
#if defined(MCU_SAMD51)
mp_hal_ticks_cpu_enable();
#endif
#if MICROPY_PY_MACHINE_RTC
machine_rtc_start(false);
#endif
}
#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_UART

View File

@ -8,6 +8,6 @@ MEMORY
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 120K
}
/* Location from which mboot is allowed to write to flash.
Must be the start of a flash erase sector. */
_mboot_writable_flash_start = ORIGIN(FLASH_BL) + LENGTH(FLASH_BL);
/* Location of protected flash area which must not be modified, because mboot lives there. */
_mboot_protected_flash_start = ORIGIN(FLASH_BL);
_mboot_protected_flash_end_exclusive = ORIGIN(FLASH_BL) + LENGTH(FLASH_BL);

View File

@ -29,7 +29,17 @@
#include "py/mphal.h"
#include "flash.h"
#if defined(STM32G0)
#if defined(STM32F0)
#define FLASH_FLAG_ALL_ERRORS (FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR)
#elif defined(STM32F4)
#define FLASH_FLAG_ALL_ERRORS (FLASH_FLAG_EOP | FLASH_FLAG_OPERR \
| FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR)
#elif defined(STM32G0)
// These are not defined on the CMSIS header
#define FLASH_FLAG_SR_ERRORS (FLASH_FLAG_OPERR | FLASH_FLAG_PROGERR | FLASH_FLAG_WRPERR | \
FLASH_FLAG_PGAERR | FLASH_FLAG_SIZERR | FLASH_FLAG_PGSERR | \
@ -41,6 +51,15 @@
#define FLASH_FLAG_ECCR_ERRORS (FLASH_FLAG_ECCC | FLASH_FLAG_ECCD)
#endif
#define FLASH_FLAG_ALL_ERRORS (FLASH_FLAG_SR_ERRORS | FLASH_FLAG_ECCR_ERRORS)
#elif defined(STM32H7)
#define FLASH_FLAG_ALL_ERRORS (FLASH_FLAG_ALL_ERRORS_BANK1 | FLASH_FLAG_ALL_ERRORS_BANK2)
#elif defined(STM32L0) || defined(STM32L1)
#define FLASH_FLAG_ALL_ERRORS (FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR)
#endif
#if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
@ -66,12 +85,15 @@ typedef struct {
#if defined(STM32F0)
static const flash_layout_t flash_layout[] = {
{ FLASH_BASE, FLASH_PAGE_SIZE, (FLASH_BANK1_END + 1 - FLASH_BASE) / FLASH_PAGE_SIZE },
};
#define FLASH_LAYOUT_IS_HOMOGENEOUS (1)
#define FLASH_LAYOUT_START_ADDR (FLASH_BASE)
#define FLASH_LAYOUT_SECTOR_SIZE (FLASH_PAGE_SIZE)
#define FLASH_LAYOUT_NUM_SECTORS ((FLASH_BANK1_END + 1 - FLASH_BASE) / FLASH_PAGE_SIZE)
#elif defined(STM32F4)
#define FLASH_LAYOUT_IS_HOMOGENEOUS (0)
static const flash_layout_t flash_layout[] = {
{ 0x08000000, 0x04000, 4 },
{ 0x08010000, 0x10000, 1 },
@ -88,9 +110,7 @@ static const flash_layout_t flash_layout[] = {
#elif defined(STM32F7)
// FLASH_FLAG_PGSERR (Programming Sequence Error) was renamed to
// FLASH_FLAG_ERSERR (Erasing Sequence Error) in STM32F7
#define FLASH_FLAG_PGSERR FLASH_FLAG_ERSERR
#define FLASH_LAYOUT_IS_HOMOGENEOUS (0)
#if defined(STM32F722xx) || defined(STM32F723xx) || defined(STM32F732xx) || defined(STM32F733xx)
static const flash_layout_t flash_layout[] = {
@ -113,39 +133,48 @@ static const flash_layout_t flash_layout[] = {
#elif defined(STM32G0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
static const flash_layout_t flash_layout[] = {
{ (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 },
};
#define FLASH_LAYOUT_IS_HOMOGENEOUS (1)
#define FLASH_LAYOUT_START_ADDR (FLASH_BASE)
#define FLASH_LAYOUT_SECTOR_SIZE (FLASH_PAGE_SIZE)
#define FLASH_LAYOUT_NUM_SECTORS (512)
#elif defined(STM32L1)
static const flash_layout_t flash_layout[] = {
{ (uint32_t)FLASH_BASE, 0x200, 1024 },
};
#define FLASH_LAYOUT_IS_HOMOGENEOUS (1)
#define FLASH_LAYOUT_START_ADDR (FLASH_BASE)
#define FLASH_LAYOUT_SECTOR_SIZE (0x200)
#define FLASH_LAYOUT_NUM_SECTORS (1024)
#elif defined(STM32H5)
static const flash_layout_t flash_layout[] = {
{ 0x08000000, 8192, 256 },
};
#define FLASH_LAYOUT_IS_HOMOGENEOUS (1)
#define FLASH_LAYOUT_START_ADDR (FLASH_BASE_NS)
#define FLASH_LAYOUT_SECTOR_SIZE (0x2000)
#define FLASH_LAYOUT_NUM_SECTORS (256)
#elif defined(STM32H7)
static const flash_layout_t flash_layout[] = {
{ 0x08000000, 0x20000, 16 },
};
#define FLASH_LAYOUT_IS_HOMOGENEOUS (1)
#define FLASH_LAYOUT_START_ADDR (FLASH_BASE)
#define FLASH_LAYOUT_SECTOR_SIZE (0x20000)
#define FLASH_LAYOUT_NUM_SECTORS (16)
#else
#error Unsupported processor
#endif
#if defined(STM32H723xx) || defined(STM32H750xx)
#if defined(STM32H7) && !defined(DUAL_BANK)
// get the bank of a given flash address
static uint32_t get_bank(uint32_t addr) {
return FLASH_BANK_1;
}
// get the page of a given flash address
static uint32_t get_page(uint32_t addr) {
return (addr - FLASH_LAYOUT_START_ADDR) / FLASH_LAYOUT_SECTOR_SIZE;
}
#elif (defined(STM32L4) && defined(SYSCFG_MEMRMP_FB_MODE)) || defined(STM32H5) || defined(STM32H7)
// get the bank of a given flash address
@ -156,14 +185,14 @@ static uint32_t get_bank(uint32_t addr) {
if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0) {
#endif
// no bank swap
if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
if (addr < (FLASH_LAYOUT_START_ADDR + FLASH_BANK_SIZE)) {
return FLASH_BANK_1;
} else {
return FLASH_BANK_2;
}
} else {
// bank swap
if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
if (addr < (FLASH_LAYOUT_START_ADDR + FLASH_BANK_SIZE)) {
return FLASH_BANK_2;
} else {
return FLASH_BANK_1;
@ -171,34 +200,32 @@ static uint32_t get_bank(uint32_t addr) {
}
}
#if (defined(STM32L4) && defined(SYSCFG_MEMRMP_FB_MODE))
// get the page of a given flash address
static uint32_t get_page(uint32_t addr) {
if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
if (addr < (FLASH_LAYOUT_START_ADDR + FLASH_BANK_SIZE)) {
// bank 1
return (addr - FLASH_BASE) / FLASH_PAGE_SIZE;
return (addr - FLASH_LAYOUT_START_ADDR) / FLASH_LAYOUT_SECTOR_SIZE;
} else {
// bank 2
return (addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
return (addr - (FLASH_LAYOUT_START_ADDR + FLASH_BANK_SIZE)) / FLASH_LAYOUT_SECTOR_SIZE;
}
}
#endif
#elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)) || defined(STM32WB) || defined(STM32WL)
static uint32_t get_page(uint32_t addr) {
return (addr - FLASH_BASE) / FLASH_PAGE_SIZE;
return (addr - FLASH_LAYOUT_START_ADDR) / FLASH_LAYOUT_SECTOR_SIZE;
}
#elif defined(STM32G0) || defined(STM32G4)
static uint32_t get_page(uint32_t addr) {
return (addr - FLASH_BASE) / FLASH_PAGE_SIZE;
return (addr - FLASH_LAYOUT_START_ADDR) / FLASH_LAYOUT_SECTOR_SIZE;
}
static uint32_t get_bank(uint32_t addr) {
// no bank swap
if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
if (addr < (FLASH_LAYOUT_START_ADDR + FLASH_BANK_SIZE)) {
return FLASH_BANK_1;
} else {
#if defined(FLASH_OPTR_DBANK)
@ -212,13 +239,33 @@ static uint32_t get_bank(uint32_t addr) {
#endif
bool flash_is_valid_addr(uint32_t addr) {
#if FLASH_LAYOUT_IS_HOMOGENEOUS
uint32_t base = FLASH_LAYOUT_START_ADDR;
uint32_t end_of_flash = FLASH_LAYOUT_START_ADDR + FLASH_LAYOUT_NUM_SECTORS * FLASH_LAYOUT_SECTOR_SIZE;
#else
uint32_t base = flash_layout[0].base_address;
uint8_t last = MP_ARRAY_SIZE(flash_layout) - 1;
uint32_t end_of_flash = flash_layout[last].base_address +
flash_layout[last].sector_count * flash_layout[last].sector_size;
return flash_layout[0].base_address <= addr && addr < end_of_flash;
#endif
return base <= addr && addr < end_of_flash;
}
int32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size) {
#if FLASH_LAYOUT_IS_HOMOGENEOUS
if (addr >= FLASH_LAYOUT_START_ADDR) {
uint32_t sector_index = (addr - FLASH_LAYOUT_START_ADDR) / FLASH_LAYOUT_SECTOR_SIZE;
if (sector_index < FLASH_LAYOUT_NUM_SECTORS) {
if (start_addr != NULL) {
*start_addr = FLASH_LAYOUT_START_ADDR + sector_index * FLASH_LAYOUT_SECTOR_SIZE;
}
if (size != NULL) {
*size = FLASH_LAYOUT_SECTOR_SIZE;
}
return sector_index;
}
}
#else
if (addr >= flash_layout[0].base_address) {
uint32_t sector_index = 0;
for (int i = 0; i < MP_ARRAY_SIZE(flash_layout); ++i) {
@ -239,14 +286,14 @@ int32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *siz
}
}
}
#endif
return -1;
}
int flash_erase(uint32_t flash_dest, uint32_t num_word32) {
// check there is something to write
if (num_word32 == 0) {
return 0;
}
// Erase a single flash page which starts at the given address.
// The address will be converted to a bank and sector number.
int flash_erase(uint32_t flash_dest) {
const unsigned int num_sectors = 1;
#if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
// Acquire lock on the flash peripheral.
@ -269,66 +316,48 @@ int flash_erase(uint32_t flash_dest, uint32_t num_word32) {
}
#endif
// Clear pending flags (if any) and set up EraseInitStruct.
// Clear pending flags (if any).
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
// Set up EraseInitStruct...
FLASH_EraseInitTypeDef EraseInitStruct;
#if defined(STM32F0)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR);
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = flash_dest;
EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE;
#elif defined(STM32G0) || defined(STM32G4)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Page = get_page(flash_dest);
EraseInitStruct.Banks = get_bank(flash_dest);
EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE;
#elif defined(STM32L0) || defined(STM32L1)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = flash_dest;
EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE;
#elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)) || defined(STM32WB) || defined(STM32WL)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Page = get_page(flash_dest);
EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE;
#elif defined(STM32L4)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
// The sector returned by flash_get_sector_info can not be used
// as the flash has on each bank 0/1 pages 0..255
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Banks = get_bank(flash_dest);
EraseInitStruct.Page = get_page(flash_dest);
EraseInitStruct.NbPages = get_page(flash_dest + 4 * num_word32 - 1) - EraseInitStruct.Page + 1;
#else
#if defined(STM32H5)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
#elif defined(STM32H7)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS_BANK1 | FLASH_FLAG_ALL_ERRORS_BANK2);
#elif defined(STM32L1)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);
#else
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
#endif
// ... the erase type and number of pages/sectors,
#if defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32L0) \
|| defined(STM32L1) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.NbPages = num_sectors;
#elif defined(STM32F4) || defined(STM32F7) || defined(STM32H5) || defined(STM32H7)
EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
EraseInitStruct.NbSectors = num_sectors;
#if defined(FLASH_CR_PSIZE)
EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
#elif !defined(STM32H5)
EraseInitStruct.VoltageRange = 0; // unused parameter on STM32H7A3/B3
#endif
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7)
EraseInitStruct.Banks = get_bank(flash_dest);
#endif
EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL);
EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1;
#if defined(STM32H5)
EraseInitStruct.Sector &= 0x7f; // second bank should start counting at 0
#else
#error Unsupported processor
#endif
// ... and the flash bank and page/sector.
#if defined(STM32F0) || defined(STM32L0) || defined(STM32L1)
EraseInitStruct.PageAddress = flash_dest;
#elif defined(STM32G0) || defined(STM32G4) || (defined(STM32L4) && defined(SYSCFG_MEMRMP_FB_MODE))
EraseInitStruct.Page = get_page(flash_dest);
EraseInitStruct.Banks = get_bank(flash_dest);
#elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)) || defined(STM32WB) || defined(STM32WL)
EraseInitStruct.Page = get_page(flash_dest);
#elif defined(STM32F4) || defined(STM32F7)
EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL);
#elif defined(STM32H5) || defined(STM32H7)
EraseInitStruct.Banks = get_bank(flash_dest);
EraseInitStruct.Sector = get_page(flash_dest);
#else
#error Unsupported processor
#endif
// Erase the sectors.
@ -355,35 +384,6 @@ int flash_erase(uint32_t flash_dest, uint32_t num_word32) {
return mp_hal_status_to_neg_errno(status);
}
/*
// erase the sector using an interrupt
void flash_erase_it(uint32_t flash_dest, uint32_t num_word32) {
// check there is something to write
if (num_word32 == 0) {
return;
}
// unlock
HAL_FLASH_Unlock();
// Clear pending flags (if any)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
// erase the sector(s)
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL);
EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1;
if (HAL_FLASHEx_Erase_IT(&EraseInitStruct) != HAL_OK) {
// error occurred during sector erase
HAL_FLASH_Lock(); // lock the flash
return;
}
}
*/
int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
#if MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
// Acquire lock on the flash peripheral.
@ -498,47 +498,3 @@ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
return mp_hal_status_to_neg_errno(status);
}
/*
use erase, then write
void flash_erase_and_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
// check there is something to write
if (num_word32 == 0) {
return;
}
// unlock
HAL_FLASH_Unlock();
// Clear pending flags (if any)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
// erase the sector(s)
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL);
EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1;
uint32_t SectorError = 0;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
// error occurred during sector erase
HAL_FLASH_Lock(); // lock the flash
return;
}
// program the flash word by word
for (int i = 0; i < num_word32; i++) {
if (HAL_FLASH_Program(TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) {
// error occurred during flash write
HAL_FLASH_Lock(); // lock the flash
return;
}
flash_dest += 4;
src += 1;
}
// lock the flash
HAL_FLASH_Lock();
}
*/

View File

@ -28,7 +28,7 @@
bool flash_is_valid_addr(uint32_t addr);
int32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size);
int flash_erase(uint32_t flash_dest, uint32_t num_word32);
int flash_erase(uint32_t flash_dest);
int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32);
#endif // MICROPY_INCLUDED_STM32_FLASH_H

View File

@ -68,7 +68,6 @@ extern uint8_t _micropy_hw_internal_flash_storage_ram_cache_end[];
#define FLASH_FLAG_FORCE_WRITE (2)
#define FLASH_FLAG_ERASED (4)
static __IO uint8_t flash_flags = 0;
static uint32_t flash_cache_sector_id;
static uint32_t flash_cache_sector_start;
static uint32_t flash_cache_sector_size;
static uint32_t flash_tick_counter_last_write;
@ -80,7 +79,7 @@ int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg) {
switch (op) {
case BDEV_IOCTL_INIT:
flash_flags = 0;
flash_cache_sector_id = 0;
flash_cache_sector_start = (uint32_t)-1;
flash_tick_counter_last_write = 0;
return 0;
@ -110,14 +109,13 @@ int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg) {
static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) {
uint32_t flash_sector_start;
uint32_t flash_sector_size;
int32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
if (flash_sector_size > FLASH_SECTOR_SIZE_MAX) {
flash_sector_size = FLASH_SECTOR_SIZE_MAX;
}
if (flash_cache_sector_id != flash_sector_id) {
if (flash_cache_sector_start != flash_sector_start) {
flash_bdev_ioctl(BDEV_IOCTL_SYNC, 0);
memcpy((void *)CACHE_MEM_START_ADDR, (const void *)flash_sector_start, flash_sector_size);
flash_cache_sector_id = flash_sector_id;
flash_cache_sector_start = flash_sector_start;
flash_cache_sector_size = flash_sector_size;
}
@ -130,8 +128,8 @@ static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) {
static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) {
uint32_t flash_sector_start;
uint32_t flash_sector_size;
int32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
if (flash_cache_sector_id == flash_sector_id) {
flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
if (flash_cache_sector_start == flash_sector_start) {
// in cache, copy from there
return (uint8_t *)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
}
@ -159,28 +157,9 @@ static void flash_bdev_irq_handler(void) {
return;
}
// This code uses interrupts to erase the flash
/*
if (flash_erase_state == 0) {
flash_erase_it(flash_cache_sector_start, flash_cache_sector_size / 4);
flash_erase_state = 1;
return;
}
if (flash_erase_state == 1) {
// wait for erase
// TODO add timeout
#define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET)
if (!flash_erase_done()) {
return;
}
flash_erase_state = 2;
}
*/
// This code erases the flash directly, waiting for it to finish
if (!(flash_flags & FLASH_FLAG_ERASED)) {
flash_erase(flash_cache_sector_start, flash_cache_sector_size / 4);
flash_erase(flash_cache_sector_start);
flash_flags |= FLASH_FLAG_ERASED;
return;
}

View File

@ -109,15 +109,13 @@
// These bits are used to detect valid application firmware at APPLICATION_ADDR
#define APP_VALIDITY_BITS (0x00000003)
// Symbol provided by the linker, at the address in flash where mboot can start erasing/writing.
extern uint8_t _mboot_writable_flash_start;
// Symbols provided by the linker, the protected flash address range where mboot lives.
extern uint8_t _mboot_protected_flash_start;
extern uint8_t _mboot_protected_flash_end_exclusive;
// For 1ms system ticker.
volatile uint32_t systick_ms;
// The sector number of the first sector that can be erased/written.
int32_t first_writable_flash_sector;
// Global dfu state
dfu_context_t dfu_context SECTION_NOZERO_BSS;
@ -410,10 +408,10 @@ void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) {
/******************************************************************************/
// FLASH
#if defined(STM32G0)
#define FLASH_START (FLASH_BASE)
#if defined(STM32G0) || defined(STM32H5)
#define FLASH_END (FLASH_BASE + FLASH_SIZE - 1)
#elif defined(STM32H5)
#define FLASH_END (0x08000000 + 2 * 1024 * 1024)
#elif defined(STM32WB)
#define FLASH_END FLASH_END_ADDR
#endif
@ -446,30 +444,28 @@ void mp_hal_pin_config_speed(uint32_t port_pin, uint32_t speed) {
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/256*04Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
#endif
static int mboot_flash_mass_erase(void) {
// Erase all flash pages after mboot.
uint32_t start_addr = (uint32_t)&_mboot_writable_flash_start;
uint32_t num_words = (FLASH_END + 1 - start_addr) / sizeof(uint32_t);
int ret = flash_erase(start_addr, num_words);
return ret;
static bool flash_is_modifiable_addr_range(uint32_t addr, uint32_t len) {
return addr + len < (uint32_t)&_mboot_protected_flash_start
|| addr >= (uint32_t)&_mboot_protected_flash_end_exclusive;
}
static int mboot_flash_page_erase(uint32_t addr, uint32_t *next_addr) {
// Compute start and end address of the sector being erased.
uint32_t sector_size = 0;
uint32_t sector_start = 0;
int32_t sector = flash_get_sector_info(addr, &sector_start, &sector_size);
if (sector < first_writable_flash_sector) {
int ret = flash_get_sector_info(addr, &sector_start, &sector_size);
*next_addr = sector_start + sector_size;
if (ret < 0 || !flash_is_modifiable_addr_range(addr, *next_addr - addr)) {
// Don't allow to erase the sector with this bootloader in it, or invalid sectors
dfu_context.status = DFU_STATUS_ERROR_ADDRESS;
dfu_context.error = (sector == 0) ? MBOOT_ERROR_STR_OVERWRITE_BOOTLOADER_IDX
: MBOOT_ERROR_STR_INVALID_ADDRESS_IDX;
dfu_context.error = (ret < 0) ? MBOOT_ERROR_STR_INVALID_ADDRESS_IDX
: MBOOT_ERROR_STR_OVERWRITE_BOOTLOADER_IDX;
return -MBOOT_ERRNO_FLASH_ERASE_DISALLOWED;
}
*next_addr = sector_start + sector_size;
// Erase the flash page.
int ret = flash_erase(sector_start, sector_size / sizeof(uint32_t));
ret = flash_erase(sector_start);
if (ret != 0) {
return ret;
}
@ -484,13 +480,30 @@ static int mboot_flash_page_erase(uint32_t addr, uint32_t *next_addr) {
return 0;
}
static int mboot_flash_mass_erase(void) {
// Erase all flash pages except those disallowed because they overlap with mboot.
uint32_t addr = FLASH_START;
while (addr <= FLASH_END) {
int ret = mboot_flash_page_erase(addr, &addr);
if (ret != 0 && ret != -MBOOT_ERRNO_FLASH_ERASE_DISALLOWED) {
return ret;
}
}
// Reset any errors from disallowed page erases.
dfu_context.status = DFU_STATUS_OK;
dfu_context.error = 0;
return 0;
}
static int mboot_flash_write(uint32_t addr, const uint8_t *src8, size_t len) {
int32_t sector = flash_get_sector_info(addr, NULL, NULL);
if (sector < first_writable_flash_sector) {
bool valid = flash_is_valid_addr(addr);
if (!valid || !flash_is_modifiable_addr_range(addr, len)) {
// Don't allow to write the sector with this bootloader in it, or invalid sectors.
dfu_context.status = DFU_STATUS_ERROR_ADDRESS;
dfu_context.error = (sector == 0) ? MBOOT_ERROR_STR_OVERWRITE_BOOTLOADER_IDX
: MBOOT_ERROR_STR_INVALID_ADDRESS_IDX;
dfu_context.error = (!valid) ? MBOOT_ERROR_STR_INVALID_ADDRESS_IDX
: MBOOT_ERROR_STR_OVERWRITE_BOOTLOADER_IDX;
return -MBOOT_ERRNO_FLASH_WRITE_DISALLOWED;
}
@ -1496,12 +1509,6 @@ enter_bootloader:
__ASM volatile ("msr basepri_max, %0" : : "r" (pri) : "memory");
#endif
// Compute the first erasable/writable internal flash sector.
first_writable_flash_sector = flash_get_sector_info((uint32_t)&_mboot_writable_flash_start, NULL, NULL);
if (first_writable_flash_sector < 0) {
first_writable_flash_sector = INT32_MAX;
}
#if defined(MBOOT_SPIFLASH_ADDR)
MBOOT_SPIFLASH_SPIFLASH->config = MBOOT_SPIFLASH_CONFIG;
mp_spiflash_init(MBOOT_SPIFLASH_SPIFLASH);

View File

@ -9,6 +9,6 @@ MEMORY
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 120K
}
/* Location from which mboot is allowed to write to flash.
Must be the start of a flash erase sector. */
_mboot_writable_flash_start = ORIGIN(FLASH_BL) + LENGTH(FLASH_BL);
/* Location of protected flash area which must not be modified, because mboot lives there. */
_mboot_protected_flash_start = ORIGIN(FLASH_BL);
_mboot_protected_flash_end_exclusive = ORIGIN(FLASH_BL) + LENGTH(FLASH_BL);

View File

@ -268,11 +268,6 @@ typedef long mp_off_t;
// Configuration for shared/runtime/softtimer.c.
#define MICROPY_SOFT_TIMER_TICKS_MS uwTick
// Prevent the "LWIP task" from running.
#define MICROPY_PY_LWIP_ENTER MICROPY_PY_PENDSV_ENTER
#define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER
#define MICROPY_PY_LWIP_EXIT MICROPY_PY_PENDSV_EXIT
#ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-stm32"
#endif

View File

@ -53,6 +53,11 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable
#define MICROPY_PY_PENDSV_REENTER atomic_state = raise_irq_pri(IRQ_PRI_PENDSV);
#define MICROPY_PY_PENDSV_EXIT restore_irq_pri(atomic_state);
// Prevent the "lwIP task" from running.
#define MICROPY_PY_LWIP_ENTER MICROPY_PY_PENDSV_ENTER
#define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER
#define MICROPY_PY_LWIP_EXIT MICROPY_PY_PENDSV_EXIT
// Timing functions.
#if __CORTEX_M == 0

View File

@ -221,12 +221,6 @@ static inline unsigned long mp_random_seed_init(void) {
#include <stdio.h>
#endif
// In lieu of a WFI(), slow down polling from being a tight loop.
//
// Note that we don't delay for the full TIMEOUT_MS, as execution
// can't be woken from the delay.
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) mp_hal_delay_us(500)
// Configure the implementation of machine.idle().
#include <sched.h>
#define MICROPY_UNIX_MACHINE_IDLE sched_yield();

View File

@ -36,6 +36,12 @@
#define MICROPY_END_ATOMIC_SECTION(x) (void)x; mp_thread_unix_end_atomic_section()
#endif
// In lieu of a WFI(), slow down polling from being a tight loop.
//
// Note that we don't delay for the full TIMEOUT_MS, as execution
// can't be woken from the delay.
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) mp_hal_delay_us(500)
void mp_hal_set_interrupt_char(char c);
#define mp_hal_stdio_poll unused // this is not implemented, nor needed

View File

@ -224,15 +224,6 @@ typedef long mp_off_t;
#include "realpath.h"
#include "init.h"
#include "sleep.h"
#if MICROPY_ENABLE_SCHEDULER
// Use minimum 1mSec sleep to make sure there is effectively a wait period:
// something like usleep(500) truncates and ends up calling Sleep(0).
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) msec_sleep(MAX(1.0, (double)(TIMEOUT_MS)))
#else
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) /* No-op */
#endif
#ifdef __GNUC__
#define MP_NOINLINE __attribute__((noinline))

View File

@ -279,10 +279,10 @@ int usleep(__int64 usec) {
#endif
void mp_hal_delay_ms(mp_uint_t ms) {
#ifdef MICROPY_EVENT_POLL_HOOK
#if MICROPY_ENABLE_SCHEDULER
mp_uint_t start = mp_hal_ticks_ms();
while (mp_hal_ticks_ms() - start < ms) {
MICROPY_EVENT_POLL_HOOK
mp_event_wait_ms(1);
}
#else
msec_sleep((double)ms);

View File

@ -27,6 +27,17 @@
#include "sleep.h"
#include "ports/unix/mphalport.h"
// Don't use the unix version of this macro.
#undef MICROPY_INTERNAL_WFE
#if MICROPY_ENABLE_SCHEDULER
// Use minimum 1mSec sleep to make sure there is effectively a wait period:
// something like usleep(500) truncates and ends up calling Sleep(0).
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) msec_sleep(MAX(1.0, (double)(TIMEOUT_MS)))
#else
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) /* No-op */
#endif
#define MICROPY_HAL_HAS_VT100 (0)
void mp_hal_move_cursor_back(unsigned int pos);

View File

@ -30,9 +30,9 @@
// as well as a fallback to generate MICROPY_GIT_TAG if the git repo or tags
// are unavailable.
#define MICROPY_VERSION_MAJOR 1
#define MICROPY_VERSION_MINOR 22
#define MICROPY_VERSION_MINOR 23
#define MICROPY_VERSION_MICRO 0
#define MICROPY_VERSION_PRERELEASE 0
#define MICROPY_VERSION_PRERELEASE 1
// Combined version as a 32-bit number for convenience to allow version
// comparison. Doesn't include prerelease state.

View File

@ -181,9 +181,9 @@ SSL/TLS tests in `multi_net` and `net_inet` use a
self-signed key/cert pair that is randomly generated and to be used for
testing/demonstration only. You should always generate your own key/cert.
To generate a new self-signed key/cert pair with openssl do:
To generate a new self-signed RSA key/cert pair with openssl do:
```
$ openssl req -x509 -newkey rsa:4096 -keyout rsa_key.pem -out rsa_cert.pem -days 365 -nodes
$ openssl req -x509 -newkey rsa:2048 -keyout rsa_key.pem -out rsa_cert.pem -days 365 -nodes -subj '/CN=micropython.local/O=MicroPython/C=AU'
```
In this case CN is: micropython.local
@ -192,3 +192,9 @@ Convert them to DER format:
$ openssl rsa -in rsa_key.pem -out rsa_key.der -outform DER
$ openssl x509 -in rsa_cert.pem -out rsa_cert.der -outform DER
```
To test elliptic curve key/cert pairs, create a key then a certificate using:
```
$ openssl ecparam -name prime256v1 -genkey -noout -out ec_key.der -outform DER
$ openssl req -new -x509 -key ec_key.der -out ec_cert.der -outform DER -days 365 -nodes -subj '/CN=micropython.local/O=MicroPython/C=AU'
```

View File

@ -1,4 +1,4 @@
# test bytearray with its re-use of byte functions
# test bytearray with its reuse of byte functions
print(bytearray(b"hello world").find(b"ll"))
print(bytearray(b"hello\x00world").rfind(b"l"))

View File

@ -57,7 +57,7 @@ def test(bdev, vfs_class):
break
vfs.mkdir(dname)
# Also create a fully drained iterator and ensure trying to re-use it
# Also create a fully drained iterator and ensure trying to reuse it
# throws the correct exception.
idir_emptied = vfs.ilistdir("/")
l = list(idir_emptied)

View File

@ -57,7 +57,7 @@ def test(bdev, vfs_class):
break
vfs.mkdir(dname)
# Also create a fully drained iterator and ensure trying to re-use it
# Also create a fully drained iterator and ensure trying to reuse it
# throws the correct exception.
idir_emptied = vfs.ilistdir("/")
l = list(idir_emptied)

View File

@ -37,7 +37,7 @@ def test(testdir):
break
vfs.mkdir(dname)
# Also create a fully drained iterator and ensure trying to re-use it
# Also create a fully drained iterator and ensure trying to reuse it
# throws the correct exception.
idir_emptied = vfs.ilistdir("/")
l = list(idir_emptied)

View File

@ -1,2 +1,2 @@
# micropython is always builtin and cannot be overriden by the filesystem.
# micropython is always builtin and cannot be overridden by the filesystem.
print("ERROR: micropython from filesystem")

View File

@ -1,2 +1,2 @@
# sys is always builtin and cannot be overriden by the filesystem.
# sys is always builtin and cannot be overridden by the filesystem.
print("ERROR: sys from filesystem")

View File

@ -1,3 +1,3 @@
# usys (and any u-prefix) is always builtin and cannot be overriden by the
# usys (and any u-prefix) is always builtin and cannot be overridden by the
# filesystem.
print("ERROR: usys from filesystem")

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/rsa_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "rsa_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/rsa_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "rsa_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/rsa_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "rsa_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/rsa_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "rsa_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

Binary file not shown.

Binary file not shown.

View File

@ -10,8 +10,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
certfile = "multi_net/rsa_cert.der"
keyfile = "multi_net/rsa_key.der"
certfile = "rsa_cert.der"
keyfile = "rsa_key.der"
try:
os.stat(certfile)

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/rsa_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "rsa_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

View File

@ -12,8 +12,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/rsa_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "rsa_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
certfile = "multi_net/rsa_cert.der"
keyfile = "multi_net/rsa_key.der"
certfile = "rsa_cert.der"
keyfile = "rsa_key.der"
try:
os.stat(certfile)

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/rsa_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "rsa_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/rsa_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "rsa_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/rsa_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "rsa_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

View File

@ -11,8 +11,8 @@ except ImportError:
PORT = 8000
# These are test certificates. See tests/README.md for details.
cert = cafile = "multi_net/expired_cert.der"
key = "multi_net/rsa_key.der"
cert = cafile = "expired_cert.der"
key = "rsa_key.der"
try:
os.stat(cafile)

View File

@ -27,13 +27,15 @@ import pyboard
if os.name == "nt":
CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3.exe")
MICROPYTHON = os.getenv(
"MICROPY_MICROPYTHON", test_dir + "/../ports/windows/build-standard/micropython.exe"
MICROPYTHON = os.path.abspath(
os.getenv(
"MICROPY_MICROPYTHON", test_dir + "/../ports/windows/build-standard/micropython.exe"
)
)
else:
CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3")
MICROPYTHON = os.getenv(
"MICROPY_MICROPYTHON", test_dir + "/../ports/unix/build-standard/micropython"
MICROPYTHON = os.path.abspath(
os.getenv("MICROPY_MICROPYTHON", test_dir + "/../ports/unix/build-standard/micropython")
)
# For diff'ing test output
@ -155,6 +157,7 @@ class PyInstance:
class PyInstanceSubProcess(PyInstance):
def __init__(self, argv, env=None):
self.argv = argv
self.cwd = None
self.env = {n: v for n, v in (i.split("=") for i in env)} if env else None
self.popen = None
self.finished = True
@ -163,8 +166,9 @@ class PyInstanceSubProcess(PyInstance):
return self.argv[0].rsplit("/")[-1]
def prepare_script_from_file(self, filename, prepend, append):
# Make tests run in an isolated environment (i.e. `import io` would
# otherwise get the `tests/io` directory).
# Make tests run in the directory of the test file, and in an isolated environment
# (i.e. `import io` would otherwise get the `tests/io` directory).
self.cwd = os.path.dirname(filename)
remove_cwd_from_sys_path = b"import sys\nsys.path.remove('')\n\n"
return remove_cwd_from_sys_path + super().prepare_script_from_file(
filename, prepend, append
@ -179,6 +183,7 @@ class PyInstanceSubProcess(PyInstance):
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
input=script,
cwd=self.cwd,
env=self.env,
)
output = p.stdout
@ -192,6 +197,7 @@ class PyInstanceSubProcess(PyInstance):
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
cwd=self.cwd,
env=self.env,
)
self.finished = False

View File

@ -6,6 +6,7 @@ import sys
import platform
import argparse
import inspect
import json
import re
from glob import glob
import multiprocessing
@ -47,6 +48,8 @@ else:
# (not site packages which may clash with u-module names), and improve start up time.
CPYTHON3_CMD = [CPYTHON3, "-BS"]
# File with the test results.
RESULTS_FILE = "_results.json"
# For diff'ing test output
DIFF = os.getenv("MICROPY_DIFF", "diff -u")
@ -173,20 +176,25 @@ def run_script_on_remote_target(pyb, args, test_file, is_special):
return had_crash, output_mupy
def run_micropython(pyb, args, test_file, is_special=False):
special_tests = (
special_tests = [
base_path(file)
for file in (
"micropython/meminfo.py",
"basics/bytes_compare3.py",
"basics/builtin_help.py",
"thread/thread_exc2.py",
"esp32/partition_ota.py",
)
]
def run_micropython(pyb, args, test_file, test_file_abspath, is_special=False):
had_crash = False
if pyb is None:
# run on PC
if (
test_file.startswith(("cmdline/", base_path("feature_check/")))
or test_file in special_tests
test_file_abspath.startswith((base_path("cmdline/"), base_path("feature_check/")))
or test_file_abspath in special_tests
):
# special handling for tests of the unix cmdline program
is_special = True
@ -202,7 +210,7 @@ def run_micropython(pyb, args, test_file, is_special=False):
# run the test, possibly with redirected input
try:
if "repl_" in test_file:
if os.path.basename(test_file).startswith("repl_"):
# Need to use a PTY to test command line editing
try:
import pty
@ -280,7 +288,7 @@ def run_micropython(pyb, args, test_file, is_special=False):
mpy_modname = os.path.splitext(os.path.basename(mpy_filename))[0]
cmdlist.extend(["-m", mpy_modname])
else:
cmdlist.append(os.path.abspath(test_file))
cmdlist.append(test_file_abspath)
# run the actual test
try:
@ -313,7 +321,7 @@ def run_micropython(pyb, args, test_file, is_special=False):
if is_special and not had_crash and b"\nSKIP\n" in output_mupy:
return b"SKIP\n"
if is_special or test_file in special_tests:
if is_special or test_file_abspath in special_tests:
# convert parts of the output that are not stable across runs
with open(test_file + ".exp", "rb") as f:
lines_exp = []
@ -357,11 +365,12 @@ def run_micropython(pyb, args, test_file, is_special=False):
return output_mupy
def run_feature_check(pyb, args, base_path, test_file):
def run_feature_check(pyb, args, test_file):
if pyb is not None and test_file.startswith("repl_"):
# REPL feature tests will not run via pyboard because they require prompt interactivity
return b""
return run_micropython(pyb, args, base_path("feature_check", test_file), is_special=True)
test_file_path = base_path("feature_check", test_file)
return run_micropython(pyb, args, test_file_path, test_file_path, is_special=True)
class ThreadSafeCounter:
@ -416,57 +425,57 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
# run-tests.py script itself so use base_path.
# Check if micropython.native is supported, and skip such tests if it's not
output = run_feature_check(pyb, args, base_path, "native_check.py")
output = run_feature_check(pyb, args, "native_check.py")
if output != b"native\n":
skip_native = True
# Check if arbitrary-precision integers are supported, and skip such tests if it's not
output = run_feature_check(pyb, args, base_path, "int_big.py")
output = run_feature_check(pyb, args, "int_big.py")
if output != b"1000000000000000000000000000000000000000000000\n":
skip_int_big = True
# Check if bytearray is supported, and skip such tests if it's not
output = run_feature_check(pyb, args, base_path, "bytearray.py")
output = run_feature_check(pyb, args, "bytearray.py")
if output != b"bytearray\n":
skip_bytearray = True
# Check if set type (and set literals) is supported, and skip such tests if it's not
output = run_feature_check(pyb, args, base_path, "set_check.py")
output = run_feature_check(pyb, args, "set_check.py")
if output != b"{1}\n":
skip_set_type = True
# Check if slice is supported, and skip such tests if it's not
output = run_feature_check(pyb, args, base_path, "slice.py")
output = run_feature_check(pyb, args, "slice.py")
if output != b"slice\n":
skip_slice = True
# Check if async/await keywords are supported, and skip such tests if it's not
output = run_feature_check(pyb, args, base_path, "async_check.py")
output = run_feature_check(pyb, args, "async_check.py")
if output != b"async\n":
skip_async = True
# Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not
output = run_feature_check(pyb, args, base_path, "const.py")
output = run_feature_check(pyb, args, "const.py")
if output != b"1\n":
skip_const = True
# Check if __rOP__ special methods are supported, and skip such tests if it's not
output = run_feature_check(pyb, args, base_path, "reverse_ops.py")
output = run_feature_check(pyb, args, "reverse_ops.py")
if output == b"TypeError\n":
skip_revops = True
# Check if io module exists, and skip such tests if it doesn't
output = run_feature_check(pyb, args, base_path, "io_module.py")
output = run_feature_check(pyb, args, "io_module.py")
if output != b"io\n":
skip_io_module = True
# Check if fstring feature is enabled, and skip such tests if it doesn't
output = run_feature_check(pyb, args, base_path, "fstring.py")
output = run_feature_check(pyb, args, "fstring.py")
if output != b"a=1\n":
skip_fstring = True
# Check if @micropython.asm_thumb supports Thumb2 instructions, and skip such tests if it doesn't
output = run_feature_check(pyb, args, base_path, "inlineasm_thumb2.py")
output = run_feature_check(pyb, args, "inlineasm_thumb2.py")
if output != b"thumb2\n":
skip_tests.add("inlineasm/asmbcc.py")
skip_tests.add("inlineasm/asmbitops.py")
@ -481,23 +490,23 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
skip_tests.add("inlineasm/asmspecialregs.py")
# Check if emacs repl is supported, and skip such tests if it's not
t = run_feature_check(pyb, args, base_path, "repl_emacs_check.py")
t = run_feature_check(pyb, args, "repl_emacs_check.py")
if "True" not in str(t, "ascii"):
skip_tests.add("cmdline/repl_emacs_keys.py")
# Check if words movement in repl is supported, and skip such tests if it's not
t = run_feature_check(pyb, args, base_path, "repl_words_move_check.py")
t = run_feature_check(pyb, args, "repl_words_move_check.py")
if "True" not in str(t, "ascii"):
skip_tests.add("cmdline/repl_words_move.py")
upy_byteorder = run_feature_check(pyb, args, base_path, "byteorder.py")
upy_float_precision = run_feature_check(pyb, args, base_path, "float.py")
upy_byteorder = run_feature_check(pyb, args, "byteorder.py")
upy_float_precision = run_feature_check(pyb, args, "float.py")
try:
upy_float_precision = int(upy_float_precision)
except ValueError:
upy_float_precision = 0
has_complex = run_feature_check(pyb, args, base_path, "complex.py") == b"complex\n"
has_coverage = run_feature_check(pyb, args, base_path, "coverage.py") == b"coverage\n"
has_complex = run_feature_check(pyb, args, "complex.py") == b"complex\n"
has_coverage = run_feature_check(pyb, args, "coverage.py") == b"coverage\n"
cpy_byteorder = subprocess.check_output(
CPYTHON3_CMD + [base_path("feature_check/byteorder.py")]
)
@ -562,18 +571,23 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
skip_tests.add("cmdline/repl_sys_ps1_ps2.py")
skip_tests.add("extmod/ssl_poll.py")
# Some tests shouldn't be run on a PC
if args.target == "unix":
# unix build does not have the GIL so can't run thread mutation tests
# Skip thread mutation tests on targets that don't have the GIL.
if args.target in ("rp2", "unix"):
for t in tests:
if t.startswith("thread/mutate_"):
skip_tests.add(t)
# Skip thread tests that require many threads on targets that don't support multiple threads.
if args.target == "rp2":
skip_tests.add("thread/stress_heap.py")
skip_tests.add("thread/thread_lock2.py")
skip_tests.add("thread/thread_lock3.py")
skip_tests.add("thread/thread_shared2.py")
# Some tests shouldn't be run on pyboard
if args.target != "unix":
skip_tests.add("basics/exception_chain.py") # warning is not printed
skip_tests.add("micropython/meminfo.py") # output is very different to PC output
skip_tests.add("extmod/machine_mem.py") # raw memory access not supported
if args.target == "wipy":
skip_tests.add("misc/print_exception.py") # requires error reporting full
@ -665,6 +679,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
def run_one_test(test_file):
test_file = test_file.replace("\\", "/")
test_file_abspath = os.path.abspath(test_file).replace("\\", "/")
if args.filters:
# Default verdict is the opposit of the first action
@ -725,7 +740,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
# run CPython to work out expected output
try:
output_expected = subprocess.check_output(
CPYTHON3_CMD + [os.path.abspath(test_file)],
CPYTHON3_CMD + [test_file_abspath],
cwd=os.path.dirname(test_file),
stderr=subprocess.STDOUT,
)
@ -742,7 +757,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
return
# run MicroPython
output_mupy = run_micropython(pyb, args, test_file)
output_mupy = run_micropython(pyb, args, test_file, test_file_abspath)
if output_mupy == b"SKIP\n":
print("skip ", test_file)
@ -765,7 +780,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
with open(filename_mupy, "wb") as f:
f.write(output_mupy)
print("FAIL ", test_file)
failed_tests.append(test_name)
failed_tests.append((test_name, test_file))
test_count.increment()
@ -779,6 +794,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
for test in tests:
run_one_test(test)
# Leave RESULTS_FILE untouched here for future runs.
if args.list_tests:
return True
@ -793,8 +809,26 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
if len(skipped_tests) > 0:
print("{} tests skipped: {}".format(len(skipped_tests), " ".join(skipped_tests)))
failed_tests = sorted(failed_tests.value)
# Serialize regex added by append_filter.
def to_json(obj):
if isinstance(obj, re.Pattern):
return obj.pattern
return obj
with open(os.path.join(result_dir, RESULTS_FILE), "w") as f:
json.dump(
{"args": vars(args), "failed_tests": [test[1] for test in failed_tests]},
f,
default=to_json,
)
if len(failed_tests) > 0:
print("{} tests failed: {}".format(len(failed_tests), " ".join(failed_tests)))
print(
"{} tests failed: {}".format(
len(failed_tests), " ".join(test[0] for test in failed_tests)
)
)
return False
# all tests succeeded
@ -910,6 +944,11 @@ the last matching regex is used:
action="store_true",
help="delete the .exp and .out files from failed tests and exit",
)
cmd_parser.add_argument(
"--run-failures",
action="store_true",
help="re-run only the failed tests",
)
args = cmd_parser.parse_args()
if args.print_failures:
@ -926,6 +965,7 @@ the last matching regex is used:
os.path.join(args.result_dir, "*.out")
):
os.remove(f)
rm_f(os.path.join(args.result_dir, RESULTS_FILE))
sys.exit(0)
@ -974,7 +1014,19 @@ the last matching regex is used:
else:
raise ValueError("target must be one of %s" % ", ".join(LOCAL_TARGETS + EXTERNAL_TARGETS))
if len(args.files) == 0:
if args.run_failures and (any(args.files) or args.test_dirs is not None):
raise ValueError(
"--run-failures cannot be used together with files or --test-dirs arguments"
)
if args.run_failures:
results_file = os.path.join(args.result_dir, RESULTS_FILE)
if os.path.exists(results_file):
with open(results_file, "r") as f:
tests = json.load(f)["failed_tests"]
else:
tests = []
elif len(args.files) == 0:
if args.test_dirs is None:
test_dirs = (
"basics",
@ -988,7 +1040,7 @@ the last matching regex is used:
elif args.target in ("renesas-ra"):
test_dirs += ("float", "inlineasm", "renesas-ra")
elif args.target == "rp2":
test_dirs += ("float", "stress", "inlineasm")
test_dirs += ("float", "stress", "inlineasm", "thread")
elif args.target in ("esp8266", "esp32", "minimal", "nrf"):
test_dirs += ("float",)
elif args.target == "wipy":

View File

@ -19,6 +19,7 @@ _TIMEOUT_MS = 10000
n = 0 # How many times the task successfully ran.
t = None # Start time of test, assigned here to preallocate entry in globals dict.
thread_run = True # If the thread should continue running.
def task(x):
@ -27,7 +28,7 @@ def task(x):
def thread():
while True:
while thread_run:
try:
micropython.schedule(task, None)
except RuntimeError:
@ -36,13 +37,21 @@ def thread():
for i in range(8):
_thread.start_new_thread(thread, ())
try:
_thread.start_new_thread(thread, ())
except OSError:
# System cannot create a new thead, so stop trying to create them.
break
# Wait up to 10 seconds for 10000 tasks to be scheduled.
t = time.ticks_ms()
while n < _NUM_TASKS and time.ticks_diff(time.ticks_ms(), t) < _TIMEOUT_MS:
pass
# Stop all threads.
thread_run = False
time.sleep_ms(20)
if n < _NUM_TASKS:
# Not all the tasks were scheduled, likely the scheduler stopped working.
print(n)

View File

@ -16,21 +16,34 @@ def thread_entry(n):
data[i] = data[i]
gc.collect()
# print whether the data remains intact and indicate we are finished
# check whether the data remains intact and indicate we are finished
with lock:
print(list(data) == list(range(256)))
global n_finished
global n_correct, n_finished
n_correct += list(data) == list(range(256))
n_finished += 1
lock = _thread.allocate_lock()
n_thread = 4
n_thread = 0
n_thread_max = 4
n_correct = 0
n_finished = 0
# spawn threads
for i in range(n_thread):
_thread.start_new_thread(thread_entry, (10,))
for _ in range(n_thread_max):
try:
_thread.start_new_thread(thread_entry, (10,))
n_thread += 1
except OSError:
# System cannot create a new thead, so stop trying to create them.
break
# also run the function on this main thread
thread_entry(10)
n_thread += 1
# busy wait for threads to finish
while n_finished < n_thread:
pass
print(n_correct == n_finished)

View File

@ -5,7 +5,12 @@
import _thread
# Initialise variables (also preallocate their spot in the globals dict so the
# globals dict is not resized while threads are running).
tid = None
tid_main = None
new_tid = None
finished = False
def thread_entry():
@ -19,7 +24,6 @@ def thread_entry():
tid_main = _thread.get_ident()
print("main", type(tid_main) == int, tid_main != 0)
finished = False
new_tid = _thread.start_new_thread(thread_entry, ())
while not finished:

View File

@ -36,14 +36,18 @@ output_lock = _thread.allocate_lock()
# spawn threads to do the jobs
for i in range(4):
_thread.start_new_thread(thread_entry, ())
try:
_thread.start_new_thread(thread_entry, ())
except OSError:
# System cannot create a new thead, so stop trying to create them.
break
# wait for the jobs to complete
while True:
with jobs_lock:
if len(output) == n_jobs:
break
time.sleep(1)
time.sleep(0)
# sort and print the results
output.sort(key=lambda x: x[0])

View File

@ -24,16 +24,26 @@ def th(base, n):
lock = _thread.allocate_lock()
n_thread = 4
n_thread = 0
n_thread_max = 4
n_finished = 0
n_qstr_per_thread = 100 # make 1000 for a more stressful test (uses more heap)
# spawn threads
for i in range(n_thread):
_thread.start_new_thread(th, (i * n_qstr_per_thread, n_qstr_per_thread))
for _ in range(n_thread_max):
try:
_thread.start_new_thread(th, (n_thread * n_qstr_per_thread, n_qstr_per_thread))
n_thread += 1
except OSError:
# System cannot create a new thead, so stop trying to create them.
break
# also run the function on this main thread
th(n_thread * n_qstr_per_thread, n_qstr_per_thread)
n_thread += 1
# wait for threads to finish
while n_finished < n_thread:
time.sleep(1)
time.sleep(0)
print("pass")

View File

@ -18,15 +18,25 @@ def thread_entry(n, tup):
lock = _thread.allocate_lock()
n_thread = 2
n_thread = 0
n_thread_max = 2
n_finished = 0
# the shared data structure
tup = (1, 2, 3, 4)
# spawn threads
for i in range(n_thread):
_thread.start_new_thread(thread_entry, (100, tup))
for _ in range(n_thread_max):
try:
_thread.start_new_thread(thread_entry, (100, tup))
n_thread += 1
except OSError:
# System cannot create a new thead, so stop trying to create them.
break
# also run the function on this main thread
thread_entry(100, tup)
n_thread += 1
# busy wait for threads to finish
while n_finished < n_thread:

View File

@ -12,7 +12,8 @@ else:
import _thread
lock = _thread.allocate_lock()
n_thread = 4
n_thread = 0
n_thread_max = 4
n_finished = 0
@ -24,10 +25,20 @@ def thread_entry(t):
n_finished += 1
for i in range(n_thread):
_thread.start_new_thread(thread_entry, (10 * i,))
# spawn threads
for _ in range(n_thread_max):
try:
_thread.start_new_thread(thread_entry, (10 * n_thread,))
n_thread += 1
except OSError:
# System cannot create a new thead, so stop trying to create them.
break
# also run the function on this main thread
thread_entry(10 * n_thread)
n_thread += 1
# wait for threads to finish
while n_finished < n_thread:
sleep_ms(100)
print("done", n_thread)
print("done")

View File

@ -0,0 +1,31 @@
# Test accuracy of sleep within a thread.
import time
import _thread
def sleep(t, valid_range):
t0 = time.time_ns()
time.sleep(t)
dt_ms = (time.time_ns() - t0) // 1_000_000
if dt_ms in valid_range:
print("dt in range", t)
else:
print("dt not in range:", dt_ms)
def thread_entry():
lock.acquire()
print("thread start")
sleep(0.2, range(180, 400))
print("thread end")
lock = _thread.allocate_lock()
lock.acquire()
_thread.start_new_thread(thread_entry, ())
print("main start")
lock.release()
sleep(0.5, range(480, 800))
print("main end")

View File

@ -2,7 +2,7 @@
echo "MicroPython change log"
for t in $(git tag | grep -v v1.0-rc1 | sort -rV); do
for t in $(git tag | grep -v -- '-rc1\|-preview' | sort -rV); do
echo ''
echo '========'
echo ''