Compare commits
32 Commits
d82915569f
...
c89910e78f
Author | SHA1 | Date |
---|---|---|
Carglglz | c89910e78f | |
stijn | bd21820b4c | |
stijn | 88d21f186b | |
stijn | ba4330ba10 | |
Damien George | 2ed976f140 | |
Damien George | e456ee40e0 | |
Damien George | 7ecff515d7 | |
Damien George | 5cb93f63fb | |
Damien George | cd6e0e1022 | |
Damien George | b6ab9e420b | |
Damien George | cf115918e6 | |
Damien George | cd0f75069c | |
Damien George | 7002a19be2 | |
Damien George | b7b99522e4 | |
Nicko van Someren | 1da45e887a | |
Nicko van Someren | f8cabe82f7 | |
darc | 80fd575c8c | |
Damien George | 42eab32a36 | |
Damien George | 0640ff3b97 | |
Damien George | d45176fc27 | |
Damien George | ee226a8b43 | |
Damien George | 7a794d0d8e | |
stijn | 2b56bab226 | |
Damien George | 0c81ffd31a | |
Damien George | f0392b8d3d | |
Damien George | a003ac2f73 | |
Damien George | 2265d70add | |
Damien George | 231fc20ce0 | |
Damien George | dc2a4e3cbd | |
Damien George | 8438c8790c | |
Damien George | c3989e398f | |
Carlosgg | 367e100ff7 |
2
LICENSE
2
LICENSE
|
@ -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)
|
||||
|
|
|
@ -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''``.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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**
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -56,6 +56,9 @@ CONFIG_LWIP_PPP_SUPPORT=y
|
|||
CONFIG_LWIP_PPP_PAP_SUPPORT=y
|
||||
CONFIG_LWIP_PPP_CHAP_SUPPORT=y
|
||||
|
||||
# IPV6
|
||||
CONFIG_LWIP_IPV6_AUTOCONFIG=y
|
||||
|
||||
# SSL
|
||||
# Use 4kiB output buffer instead of default 16kiB
|
||||
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
|
||||
|
|
|
@ -166,6 +166,9 @@ static void network_wlan_ip_event_handler(void *event_handler_arg, esp_event_bas
|
|||
ESP_LOGI("network", "GOT_IP");
|
||||
wifi_sta_connected = true;
|
||||
wifi_sta_disconn_reason = 0; // Success so clear error. (in case of new error will be replaced anyway)
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
esp_netif_create_ip6_linklocal(event->esp_netif);
|
||||
|
||||
#if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER
|
||||
if (!mdns_initialised) {
|
||||
mdns_init();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -45,6 +45,11 @@
|
|||
#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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
||||
|
|
|
@ -14,20 +14,33 @@
|
|||
#define MICROPY_EMIT_THUMB_ARMV7M (0)
|
||||
#define MICROPY_MODULE_BUILTIN_INIT (1)
|
||||
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
|
||||
|
||||
#ifndef MICROPY_PY_MATH
|
||||
#define MICROPY_PY_MATH (1)
|
||||
#define MP_NEED_LOG2 (1)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_PY_BUILTINS_COMPLEX
|
||||
#define MICROPY_PY_BUILTINS_COMPLEX (0)
|
||||
#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);
|
||||
|
|
|
@ -10,21 +10,6 @@
|
|||
// 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)
|
||||
|
|
|
@ -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,16 +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)
|
||||
#ifndef MICROPY_PY_MACHINE_ADC
|
||||
#define MICROPY_PY_MACHINE_ADC (1)
|
||||
#endif
|
||||
|
@ -148,7 +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_PLATFORM (1)
|
||||
#define MICROPY_PLATFORM_VERSION "ASF4"
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
@ -188,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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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, §or_start, §or_size);
|
||||
if (sector < first_writable_flash_sector) {
|
||||
int ret = flash_get_sector_info(addr, §or_start, §or_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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'
|
||||
```
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
|
@ -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 ''
|
||||
|
|
Loading…
Reference in New Issue