Kevin Donnelly 2024-05-04 20:28:57 +12:00
commit d5197af43b
135 zmienionych plików z 1901 dodań i 431 usunięć

Wyświetl plik

@ -8,9 +8,15 @@ on:
- 'tools/**'
- 'py/**'
- 'extmod/**'
- 'shared/**'
- 'lib/**'
- 'ports/bare-arm/**'
- 'ports/mimxrt/**'
- 'ports/minimal/**'
- 'ports/rp2/**'
- 'ports/samd/**'
- 'ports/stm32/**'
- 'ports/unix/**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}

Wyświetl plik

@ -88,10 +88,11 @@ jobs:
(cd ports/unix && gcov -o build-coverage/py ../../py/*.c || true)
(cd ports/unix && gcov -o build-coverage/extmod ../../extmod/*.c || true)
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures

3
.gitmodules vendored
Wyświetl plik

@ -65,3 +65,6 @@
[submodule "lib/libmetal"]
path = lib/libmetal
url = https://github.com/OpenAMP/libmetal.git
[submodule "lib/arduino-lib"]
path = lib/arduino-lib
url = https://github.com/arduino/arduino-lib-mpy.git

Wyświetl plik

@ -33,7 +33,7 @@ Variables
MicroPython processes local and global variables differently. Global variables
are stored and looked up from a global dictionary that is allocated on the heap
(note that each module has its own separate dict, so separate namespace).
Local variables on the other hand are are stored on the Python value stack, which may
Local variables on the other hand are stored on the Python value stack, which may
live on the C stack or on the heap. They are accessed directly by their offset
within the Python stack, which is more efficient than a global lookup in a dict.

Wyświetl plik

@ -75,6 +75,21 @@ Methods
- ``wake`` specifies the sleep mode from where this interrupt can wake
up the system.
.. method:: RTC.memory([data])
``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.
Data written to RTC user memory is persistent across restarts, including
`machine.soft_reset()` and `machine.deepsleep()`.
The maximum length of RTC user memory is 2048 bytes by default on esp32,
and 492 bytes on esp8266.
Availability: esp32, esp8266 ports.
Constants
---------

Wyświetl plik

@ -130,15 +130,25 @@ Methods
Second argument is a memoryview to read the USB control request
data for this stage. The memoryview is only valid until the
callback function returns.
callback function returns. Data in this memoryview will be the same
across each of the three stages of a single transfer.
A successful transfer consists of this callback being called in sequence
for the three stages. Generally speaking, if a device wants to do
something in response to a control request then it's best to wait until
the ACK stage to confirm the host controller completed the transfer as
expected.
The callback should return one of the following values:
- ``False`` to stall the endpoint and reject the transfer.
- ``False`` to stall the endpoint and reject the transfer. It won't
proceed to any remaining stages.
- ``True`` to continue the transfer to the next stage.
- A buffer object to provide data for this stage of the transfer.
This should be a writable buffer for an ``OUT`` direction transfer, or a
readable buffer with data for an ``IN`` direction transfer.
- A buffer object can be returned at the SETUP stage when the transfer
will send or receive additional data. Typically this is the case when
the ``wLength`` field in the request has a non-zero value. This should
be a writable buffer for an ``OUT`` direction transfer, or a readable
buffer with data for an ``IN`` direction transfer.
- ``xfer_cb`` - This callback is called whenever a non-control
transfer submitted by calling :func:`USBDevice.submit_xfer` completes.

Wyświetl plik

@ -86,7 +86,8 @@ and .mpy version.
=================== ============
MicroPython release .mpy version
=================== ============
v1.22.0 and up 6.2
v1.23.0 and up 6.3
v1.22.x 6.2
v1.20 - v1.21.0 6.1
v1.19.x 6
v1.12 - v1.18 5
@ -102,6 +103,7 @@ MicroPython repository at which the .mpy version was changed.
=================== ========================================
.mpy version change Git commit
=================== ========================================
6.2 to 6.3 bdbc869f9ea200c0d28b2bc7bfb60acd9d884e1b
6.1 to 6.2 6967ff3c581a66f73e9f3d78975f47528db39980
6 to 6.1 d94141e1473aebae0d3c63aeaa8397651ad6fa01
5 to 6 f2040bfc7ee033e48acef9f289790f3b4e6b74e5

Wyświetl plik

@ -442,6 +442,23 @@ typedef struct {
.single_status_byte = false, \
}
// Settings for the ISSI devices
#define IS25LPWP064D { \
.total_size = (1 << 23), /* 8 MiB */ \
.start_up_time_us = 5000, \
.manufacturer_id = 0x9D, \
.memory_type = 0x60, \
.capacity = 0x17, \
.max_clock_speed_mhz = 80, \
.quad_enable_bit_mask = 0x40, \
.has_sector_protection = false, \
.supports_fast_read = true, \
.supports_qspi = true, \
.supports_qspi_writes = true, \
.write_status_register_split = false, \
.single_status_byte = true, \
}
// Settings for a GENERIC device with the most common setting
#define GENERIC { \
.total_size = (1 << 21), /* 2 MiB */ \

Wyświetl plik

@ -1,3 +1,4 @@
#define MICROPY_PY_ARRAY (1)
#define MICROPY_PY_FRAMEBUF (1)
#include "py/dynruntime.h"
@ -12,7 +13,7 @@ mp_obj_full_type_t mp_type_framebuf;
#include "extmod/modframebuf.c"
mp_map_elem_t framebuf_locals_dict_table[11];
mp_map_elem_t framebuf_locals_dict_table[12];
static MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table);
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
@ -30,9 +31,10 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
framebuf_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_rect), MP_OBJ_FROM_PTR(&framebuf_rect_obj) };
framebuf_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_line), MP_OBJ_FROM_PTR(&framebuf_line_obj) };
framebuf_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_ellipse), MP_OBJ_FROM_PTR(&framebuf_ellipse_obj) };
framebuf_locals_dict_table[8] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_blit), MP_OBJ_FROM_PTR(&framebuf_blit_obj) };
framebuf_locals_dict_table[9] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_scroll), MP_OBJ_FROM_PTR(&framebuf_scroll_obj) };
framebuf_locals_dict_table[10] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_text), MP_OBJ_FROM_PTR(&framebuf_text_obj) };
framebuf_locals_dict_table[8] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_poly), MP_OBJ_FROM_PTR(&framebuf_poly_obj) };
framebuf_locals_dict_table[9] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_blit), MP_OBJ_FROM_PTR(&framebuf_blit_obj) };
framebuf_locals_dict_table[10] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_scroll), MP_OBJ_FROM_PTR(&framebuf_scroll_obj) };
framebuf_locals_dict_table[11] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_text), MP_OBJ_FROM_PTR(&framebuf_text_obj) };
MP_OBJ_TYPE_SET_SLOT(&mp_type_framebuf, locals_dict, (void*)&framebuf_locals_dict, 2);
mp_store_global(MP_QSTR_FrameBuffer, MP_OBJ_FROM_PTR(&mp_type_framebuf));

Wyświetl plik

@ -57,13 +57,6 @@
#define METAL_MAX_DEVICE_REGIONS 1
#endif
// generic/log.h
#if METAL_LOG_HANDLER_ENABLE
#include "py/mphal.h"
#undef metal_log
#define metal_log(level, ...) mp_printf(&mp_plat_print, __VA_ARGS__)
#endif
static inline void *__metal_allocate_memory(unsigned int size) {
return m_tracked_calloc(1, size);
}

Wyświetl plik

@ -156,7 +156,7 @@ static MP_DEFINE_CONST_OBJ_TYPE(
// Task class
// This is the core asyncio context with cur_task, _task_queue and CancelledError.
static mp_obj_t asyncio_context = MP_OBJ_NULL;
mp_obj_t mp_asyncio_context = MP_OBJ_NULL;
static mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 2, false);
@ -168,7 +168,7 @@ static mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
self->state = TASK_STATE_RUNNING_NOT_WAITED_ON;
self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
if (n_args == 2) {
asyncio_context = args[1];
mp_asyncio_context = args[1];
}
return MP_OBJ_FROM_PTR(self);
}
@ -186,7 +186,7 @@ static mp_obj_t task_cancel(mp_obj_t self_in) {
return mp_const_false;
}
// Can't cancel self (not supported yet).
mp_obj_t cur_task = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
mp_obj_t cur_task = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
if (self_in == cur_task) {
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("can't cancel self"));
}
@ -195,7 +195,7 @@ static mp_obj_t task_cancel(mp_obj_t self_in) {
self = MP_OBJ_TO_PTR(self->data);
}
mp_obj_t _task_queue = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__task_queue));
mp_obj_t _task_queue = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__task_queue));
// Reschedule Task as a cancelled task.
mp_obj_t dest[3];
@ -218,7 +218,7 @@ static mp_obj_t task_cancel(mp_obj_t self_in) {
task_queue_push(2, dest);
}
self->data = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_CancelledError));
self->data = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_CancelledError));
return mp_const_true;
}
@ -278,7 +278,7 @@ static mp_obj_t task_iternext(mp_obj_t self_in) {
nlr_raise(self->data);
} else {
// Put calling task on waiting queue.
mp_obj_t cur_task = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
mp_obj_t cur_task = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
mp_obj_t args[2] = { self->state, cur_task };
task_queue_push(2, args);
// Set calling task's data to this task that it waits on, to double-link it.

Wyświetl plik

@ -577,9 +577,7 @@ static mp_obj_t framebuf_ellipse(size_t n_args, const mp_obj_t *args_in) {
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_ellipse_obj, 6, 8, framebuf_ellipse);
#if MICROPY_PY_ARRAY && !MICROPY_ENABLE_DYNRUNTIME
// TODO: poly needs mp_binary_get_size & mp_binary_get_val_array which aren't
// available in dynruntime.h yet.
#if MICROPY_PY_ARRAY
static mp_int_t poly_int(mp_buffer_info_t *bufinfo, size_t index) {
return mp_obj_get_int(mp_binary_get_val_array(bufinfo->typecode, bufinfo->buf, index));
@ -696,7 +694,8 @@ static mp_obj_t framebuf_poly(size_t n_args, const mp_obj_t *args_in) {
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_poly_obj, 5, 6, framebuf_poly);
#endif // MICROPY_PY_ARRAY && !MICROPY_ENABLE_DYNRUNTIME
#endif // MICROPY_PY_ARRAY
static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) {
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args_in[0]);

Wyświetl plik

@ -28,9 +28,11 @@
#if MICROPY_PY_OPENAMP
#include <stdarg.h>
#include "py/obj.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/mpprint.h"
#include "metal/sys.h"
#include "metal/alloc.h"
@ -75,8 +77,6 @@ static const char openamp_trace_buf[128];
#endif // MICROPY_PY_OPENAMP_RSC_TABLE_ENABLE
#define debug_printf(...) // mp_printf(&mp_plat_print, __VA_ARGS__)
#if MICROPY_PY_OPENAMP_REMOTEPROC
extern mp_obj_type_t openamp_remoteproc_type;
#endif
@ -136,7 +136,7 @@ typedef struct _endpoint_obj_t {
static const mp_obj_type_t endpoint_type;
static int endpoint_recv_callback(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) {
debug_printf("endpoint_recv_callback() message received src: %lu msg len: %d\n", src, len);
metal_log(METAL_LOG_DEBUG, "endpoint_recv_callback() message received src: %lu msg len: %d\n", src, len);
endpoint_obj_t *self = metal_container_of(ept, endpoint_obj_t, ep);
if (self->callback != mp_const_none) {
mp_call_function_2(self->callback, mp_obj_new_int(src), mp_obj_new_bytearray_by_ref(len, data));
@ -174,7 +174,7 @@ static mp_obj_t endpoint_send(uint n_args, const mp_obj_t *pos_args, mp_map_t *k
mp_buffer_info_t rbuf;
mp_get_buffer_raise(pos_args[1], &rbuf, MP_BUFFER_READ);
debug_printf("endpoint_send() msg len: %d\n", rbuf.len);
metal_log(METAL_LOG_DEBUG, "endpoint_send() msg len: %d\n", rbuf.len);
int bytes = 0;
mp_int_t timeout = args[ARG_timeout].u_int;
@ -258,7 +258,7 @@ void openamp_remoteproc_notified(mp_sched_node_t *node) {
}
static void openamp_ns_callback(struct rpmsg_device *rdev, const char *name, uint32_t dest) {
debug_printf("rpmsg_new_service_callback() new service request name: %s dest %lu\n", name, dest);
metal_log(METAL_LOG_DEBUG, "rpmsg_new_service_callback() new service request name: %s dest %lu\n", name, dest);
// The remote processor advertises its presence to the host by sending
// the Name Service (NS) announcement containing the name of the channel.
virtio_dev_obj_t *virtio_device = metal_container_of(rdev, virtio_dev_obj_t, rvdev);
@ -315,6 +315,13 @@ static mp_obj_t openamp_new_service_callback(mp_obj_t ns_callback) {
}
static MP_DEFINE_CONST_FUN_OBJ_1(openamp_new_service_callback_obj, openamp_new_service_callback);
void openamp_metal_log_handler(enum metal_log_level level, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
mp_vprintf(&mp_plat_print, fmt, args);
va_end(args);
}
void openamp_init(void) {
if (MP_STATE_PORT(virtio_device) != NULL) {
// Already initialized.
@ -322,7 +329,14 @@ void openamp_init(void) {
}
struct metal_device *device;
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
struct metal_init_params metal_params = { 0 };
#if METAL_LOG_HANDLER_ENABLE
// If logging is enabled, set the default log level and handler before
// calling metal_init, to allow ports to override them in metal_sys_init.
metal_params.log_level = METAL_LOG_DEBUG;
metal_params.log_handler = openamp_metal_log_handler;
#endif
// Initialize libmetal.
metal_init(&metal_params);

Wyświetl plik

@ -46,8 +46,6 @@
#include "modopenamp.h"
#include "modopenamp_remoteproc.h"
#define DEBUG_printf(...) // mp_printf(&mp_plat_print, __VA_ARGS__)
#if !MICROPY_PY_OPENAMP
#error "MICROPY_PY_OPENAMP_REMOTEPROC requires MICROPY_PY_OPENAMP"
#endif

Wyświetl plik

@ -47,8 +47,6 @@
#if MICROPY_PY_OPENAMP_REMOTEPROC_STORE_ENABLE
#define DEBUG_printf(...) // mp_printf(&mp_plat_print, __VA_ARGS__)
// Note the initial file buffer size needs to be at least 512 to read
// enough of the elf headers on the first call to store_open(), and on
// subsequent calls to store functions, it gets reallocated if needed.
@ -70,7 +68,7 @@ void *mp_openamp_remoteproc_store_alloc(void) {
}
static int openamp_remoteproc_store_open(void *store, const char *path, const void **image_data) {
DEBUG_printf("store_open(): %s\n", path);
metal_log(METAL_LOG_DEBUG, "store_open(): %s\n", path);
mp_obj_t args[2] = {
mp_obj_new_str(path, strlen(path)),
MP_OBJ_NEW_QSTR(MP_QSTR_rb),
@ -89,7 +87,7 @@ static int openamp_remoteproc_store_open(void *store, const char *path, const vo
}
static void openamp_remoteproc_store_close(void *store) {
DEBUG_printf("store_close()\n");
metal_log(METAL_LOG_DEBUG, "store_close()\n");
openamp_remoteproc_filestore_t *fstore = store;
mp_stream_close(fstore->file);
metal_free_memory(fstore->buf);
@ -113,17 +111,17 @@ static int openamp_remoteproc_store_load(void *store, size_t offset, size_t size
// Note tracked allocs don't support realloc.
fstore->len = size;
fstore->buf = metal_allocate_memory(size);
DEBUG_printf("store_load() realloc to %lu\n", fstore->len);
metal_log(METAL_LOG_DEBUG, "store_load() realloc to %lu\n", fstore->len);
}
*data = fstore->buf;
DEBUG_printf("store_load(): pa 0x%lx offset %u size %u \n", (uint32_t)pa, offset, size);
metal_log(METAL_LOG_DEBUG, "store_load(): pa 0x%lx offset %u size %u \n", (uint32_t)pa, offset, size);
} else {
void *va = metal_io_phys_to_virt(io, pa);
if (va == NULL) {
return -EINVAL;
}
*data = va;
DEBUG_printf("store_load(): pa 0x%lx va 0x%p offset %u size %u \n", (uint32_t)pa, va, offset, size);
metal_log(METAL_LOG_DEBUG, "store_load(): pa 0x%lx va 0x%p offset %u size %u \n", (uint32_t)pa, va, offset, size);
}
mp_uint_t bytes = mp_stream_read_exactly(fstore->file, (void *)*data, size, &error);

Wyświetl plik

@ -39,6 +39,8 @@
#define PROTOCOL_TLS_CLIENT (0)
#define PROTOCOL_TLS_SERVER (1)
#define CERT_NONE (0)
// This corresponds to an SSLContext object.
typedef struct _mp_obj_ssl_context_t {
mp_obj_base_t base;
@ -155,6 +157,25 @@ static mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args
return MP_OBJ_FROM_PTR(self);
}
static void ssl_context_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (dest[0] == MP_OBJ_NULL) {
// Load attribute.
if (attr == MP_QSTR_verify_mode) {
// CERT_NONE is the only supported verify_mode value.
dest[0] = MP_OBJ_NEW_SMALL_INT(CERT_NONE);
} else {
// Continue lookup in locals_dict.
dest[1] = MP_OBJ_SENTINEL;
}
} else if (dest[1] != MP_OBJ_NULL) {
// Store attribute.
if (attr == MP_QSTR_verify_mode) {
// CERT_NONE is the only supported verify_mode value, so no need to store anything.
dest[0] = MP_OBJ_NULL;
}
}
}
static void ssl_context_load_key(mp_obj_ssl_context_t *self, mp_obj_t key_obj, mp_obj_t cert_obj) {
self->key = key_obj;
self->cert = cert_obj;
@ -199,6 +220,7 @@ static MP_DEFINE_CONST_OBJ_TYPE(
MP_QSTR_SSLContext,
MP_TYPE_FLAG_NONE,
make_new, ssl_context_make_new,
attr, ssl_context_attr,
locals_dict, &ssl_context_locals_dict
);
@ -429,6 +451,7 @@ static const mp_rom_map_elem_t mp_module_tls_globals_table[] = {
// Constants.
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_CLIENT), MP_ROM_INT(PROTOCOL_TLS_CLIENT) },
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_SERVER), MP_ROM_INT(PROTOCOL_TLS_SERVER) },
{ MP_ROM_QSTR(MP_QSTR_CERT_NONE), MP_ROM_INT(CERT_NONE) },
};
static MP_DEFINE_CONST_DICT(mp_module_tls_globals, mp_module_tls_globals_table);

Wyświetl plik

@ -543,6 +543,11 @@ static const mp_rom_map_elem_t network_cyw43_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_cyw43_config_obj) },
// Class constants.
{ MP_ROM_QSTR(MP_QSTR_IF_STA), MP_ROM_INT(MOD_NETWORK_STA_IF) },
{ MP_ROM_QSTR(MP_QSTR_IF_AP), MP_ROM_INT(MOD_NETWORK_AP_IF) },
{ MP_ROM_QSTR(MP_QSTR_SEC_OPEN), MP_ROM_INT(CYW43_AUTH_OPEN) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA_WPA2), MP_ROM_INT(CYW43_AUTH_WPA2_MIXED_PSK) },
{ MP_ROM_QSTR(MP_QSTR_PM_NONE), MP_ROM_INT(PM_NONE) },
{ MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(PM_PERFORMANCE) },
{ MP_ROM_QSTR(MP_QSTR_PM_POWERSAVE), MP_ROM_INT(PM_POWERSAVE) },

Wyświetl plik

@ -309,6 +309,15 @@ static const mp_rom_map_elem_t network_esp_hosted_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_ipconfig), MP_ROM_PTR(&network_esp_hosted_ipconfig_obj) },
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_esp_hosted_config_obj) },
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_esp_hosted_status_obj) },
// Class constants.
{ MP_ROM_QSTR(MP_QSTR_IF_STA), MP_ROM_INT(MOD_NETWORK_STA_IF) },
{ MP_ROM_QSTR(MP_QSTR_IF_AP), MP_ROM_INT(MOD_NETWORK_AP_IF) },
{ MP_ROM_QSTR(MP_QSTR_SEC_OPEN), MP_ROM_INT(ESP_HOSTED_SEC_OPEN) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WEP), MP_ROM_INT(ESP_HOSTED_SEC_WEP) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA_WPA2), MP_ROM_INT(ESP_HOSTED_SEC_WPA_WPA2_PSK) },
// For backwards compatibility.
{ MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(ESP_HOSTED_SEC_OPEN) },
{ MP_ROM_QSTR(MP_QSTR_WEP), MP_ROM_INT(ESP_HOSTED_SEC_WEP) },
{ MP_ROM_QSTR(MP_QSTR_WPA_PSK), MP_ROM_INT(ESP_HOSTED_SEC_WPA_WPA2_PSK) },

Wyświetl plik

@ -860,11 +860,17 @@ static const mp_rom_map_elem_t nina_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_ninaw10_status_obj) },
{ MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&network_ninaw10_ioctl_obj) },
// Network is not secured.
// Class constants.
{ MP_ROM_QSTR(MP_QSTR_IF_STA), MP_ROM_INT(MOD_NETWORK_STA_IF) },
{ MP_ROM_QSTR(MP_QSTR_IF_AP), MP_ROM_INT(MOD_NETWORK_AP_IF) },
{ MP_ROM_QSTR(MP_QSTR_SEC_OPEN), MP_ROM_INT(NINA_SEC_OPEN) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WEP), MP_ROM_INT(NINA_SEC_WEP) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA_WPA2), MP_ROM_INT(NINA_SEC_WPA_PSK) },
// For backwards compatibility.
{ MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(NINA_SEC_OPEN) },
// Security type WEP (40 or 104).
{ MP_ROM_QSTR(MP_QSTR_WEP), MP_ROM_INT(NINA_SEC_WEP) },
// Network secured with WPA/WPA2 personal(PSK).
{ MP_ROM_QSTR(MP_QSTR_WPA_PSK), MP_ROM_INT(NINA_SEC_WPA_PSK) },
};

Wyświetl plik

@ -221,7 +221,7 @@ static void wiznet5k_init(void) {
setSn_IMR(0, Sn_IR_RECV);
#if _WIZCHIP_ == W5100S
// Enable interrupt pin
setMR(MR2_G_IEN);
setMR2(getMR2() | MR2_G_IEN);
#endif
mp_hal_pin_input(wiznet5k_obj.pin_intn);

1
lib/arduino-lib 160000

@ -0,0 +1 @@
Subproject commit 89424753e18ed58b7d8041085c9d2e1d162f09ca

Wyświetl plik

@ -116,6 +116,10 @@ void mp_task(void *pvParameter) {
}
void *mp_task_heap = MP_PLAT_ALLOC_HEAP(MICROPY_GC_INITIAL_HEAP_SIZE);
if (mp_task_heap == NULL) {
printf("mp_task_heap allocation failed!\n");
esp_restart();
}
soft_reset:
// initialise the stack pointer for the main thread

Wyświetl plik

@ -730,6 +730,20 @@ static const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_network_ifconfig_obj) },
// Constants
{ MP_ROM_QSTR(MP_QSTR_IF_STA), MP_ROM_INT(WIFI_IF_STA)},
{ MP_ROM_QSTR(MP_QSTR_IF_AP), MP_ROM_INT(WIFI_IF_AP)},
{ MP_ROM_QSTR(MP_QSTR_SEC_OPEN), MP_ROM_INT(WIFI_AUTH_OPEN) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WEP), MP_ROM_INT(WIFI_AUTH_WEP) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA), MP_ROM_INT(WIFI_AUTH_WPA_PSK) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA2), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA_WPA2), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA2_ENT), MP_ROM_INT(WIFI_AUTH_WPA2_ENTERPRISE) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA3), MP_ROM_INT(WIFI_AUTH_WPA3_PSK) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA2_WPA3), MP_ROM_INT(WIFI_AUTH_WPA2_WPA3_PSK) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WAPI), MP_ROM_INT(WIFI_AUTH_WAPI_PSK) },
{ MP_ROM_QSTR(MP_QSTR_SEC_OWE), MP_ROM_INT(WIFI_AUTH_OWE) },
{ MP_ROM_QSTR(MP_QSTR_PM_NONE), MP_ROM_INT(WIFI_PS_NONE) },
{ MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(WIFI_PS_MIN_MODEM) },
{ MP_ROM_QSTR(MP_QSTR_PM_POWERSAVE), MP_ROM_INT(WIFI_PS_MAX_MODEM) },

Wyświetl plik

@ -96,6 +96,9 @@ COPT += -Os -DNDEBUG
LDFLAGS += --gc-sections
endif
# Flags for optional C++ source code
CXXFLAGS += $(filter-out -Wmissing-prototypes -Wold-style-definition -std=gnu99,$(CFLAGS))
# Options for mpy-cross
MPY_CROSS_FLAGS += -march=xtensa

Wyświetl plik

@ -516,6 +516,15 @@ static const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
// Constants
{ MP_ROM_QSTR(MP_QSTR_IF_STA), MP_ROM_INT(STATION_IF)},
{ MP_ROM_QSTR(MP_QSTR_IF_AP), MP_ROM_INT(SOFTAP_IF)},
{ MP_ROM_QSTR(MP_QSTR_SEC_OPEN), MP_ROM_INT(AUTH_OPEN) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WEP), MP_ROM_INT(AUTH_WEP) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA), MP_ROM_INT(AUTH_WPA_PSK) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA2), MP_ROM_INT(AUTH_WPA2_PSK) },
{ MP_ROM_QSTR(MP_QSTR_SEC_WPA_WPA2), MP_ROM_INT(AUTH_WPA_WPA2_PSK) },
{ MP_ROM_QSTR(MP_QSTR_PM_NONE), MP_ROM_INT(NONE_SLEEP_T) },
{ MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(MODEM_SLEEP_T) },
{ MP_ROM_QSTR(MP_QSTR_PM_POWERSAVE), MP_ROM_INT(LIGHT_SLEEP_T) },

Wyświetl plik

@ -172,7 +172,8 @@ SRC_HAL_IMX_C += \
$(MCU_DIR)/drivers/fsl_common_arm.c \
$(MCU_DIR)/drivers/fsl_anatop_ai.c \
$(MCU_DIR)/drivers/fsl_caam.c \
$(MCU_DIR)/drivers/fsl_lpadc.c
$(MCU_DIR)/drivers/fsl_lpadc.c \
$(MCU_DIR)/drivers/fsl_mu.c
else
SRC_HAL_IMX_C += \
$(MCU_DIR)/drivers/fsl_adc.c \
@ -267,6 +268,17 @@ ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1)
SRC_C += mpnimbleport.c
endif
# Add mimxrt-specific implementation of libmetal (and optionally OpenAMP's rproc).
# Note: libmetal code is generated via a pre-processor so ensure that runs first.
ifeq ($(MICROPY_PY_OPENAMP),1)
SRC_C += mpmetalport.c
$(BUILD)/mpmetalport.o: $(BUILD)/openamp/metal/config.h
ifeq ($(MICROPY_PY_OPENAMP_REMOTEPROC),1)
SRC_C += mpremoteprocport.c
$(BUILD)/mpremoteprocport.o: $(BUILD)/openamp/metal/config.h
endif
endif
# Math library source files
ifeq ($(MICROPY_FLOAT_IMPL),double)
LIBM_SRC_C += $(SRC_LIB_LIBM_DBL_C)

Wyświetl plik

@ -13,6 +13,8 @@ MICROPY_HW_SDRAM_SIZE = 0x4000000 # 64MB
MICROPY_PY_LWIP = 1
MICROPY_PY_SSL = 1
MICROPY_SSL_MBEDTLS = 1
MICROPY_PY_OPENAMP = 1
MICROPY_PY_OPENAMP_REMOTEPROC = 1
FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py

Wyświetl plik

@ -57,3 +57,7 @@ _gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram);
_gc_heap_start = ORIGIN(m_ocrm);
_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
#endif
/* CM4 DTCM */
_openamp_shm_region_start = 0x20220000;
_openamp_shm_region_end = 0x20230000;

Wyświetl plik

@ -87,6 +87,7 @@ int main(void) {
memcpy(&buf[0], "PYBD", 4);
mp_hal_get_mac_ascii(MP_HAL_MAC_WLAN0, 8, 4, (char *)&buf[4]);
cyw43_wifi_ap_set_ssid(&cyw43_state, 8, buf);
cyw43_wifi_ap_set_auth(&cyw43_state, CYW43_AUTH_WPA2_MIXED_PSK);
cyw43_wifi_ap_set_password(&cyw43_state, 8, (const uint8_t *)"pybd0123");
}
#endif

Wyświetl plik

@ -0,0 +1,111 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 Arduino SA
*
* 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.
*
* libmetal mimxrt port.
*/
#include "py/mperrno.h"
#include "py/mphal.h"
#include "fsl_common.h"
#include "fsl_mu.h"
#include CPU_HEADER_H
#include "metal/sys.h"
#include "metal/utilities.h"
#include "metal/device.h"
struct metal_state _metal;
static mp_sched_node_t rproc_notify_node;
#define IRQ_PRI_MU NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 10, 0)
int metal_sys_init(const struct metal_init_params *params) {
metal_unused(params);
// Init MU.
MU_Init(MUA);
// Configure and enable MU IRQs.
MU_ClearStatusFlags(MUA, kMU_GenInt0Flag);
NVIC_SetPriority(MUA_IRQn, IRQ_PRI_MU);
NVIC_EnableIRQ(MUA_IRQn);
MU_EnableInterrupts(MUA, kMU_GenInt0InterruptEnable);
#ifndef VIRTIO_USE_DCACHE
// If cache management is not enabled, configure the MPU to disable caching
// for the entire shared memory region.
ARM_MPU_Disable();
MPU->RBAR = ARM_MPU_RBAR(10, METAL_MPU_REGION_BASE);
// Normal type, not shareable, non-cacheable
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 0, 0, 0, METAL_MPU_REGION_SIZE);
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
#endif
metal_bus_register(&metal_generic_bus);
return 0;
}
void metal_sys_finish(void) {
NVIC_DisableIRQ(MUA_IRQn);
metal_bus_unregister(&metal_generic_bus);
}
unsigned int sys_irq_save_disable(void) {
return disable_irq();
}
void sys_irq_restore_enable(unsigned int state) {
enable_irq(state);
}
void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa,
size_t size, unsigned int flags) {
metal_unused(pa);
metal_unused(size);
metal_unused(flags);
return va;
}
void metal_machine_cache_flush(void *addr, unsigned int len) {
SCB_CleanDCache_by_Addr(addr, len);
}
void metal_machine_cache_invalidate(void *addr, unsigned int len) {
SCB_InvalidateDCache_by_Addr(addr, len);
}
int metal_rproc_notify(void *priv, uint32_t id) {
MU_TriggerInterrupts(MUA, kMU_GenInt0InterruptTrigger);
return 0;
}
void MUA_IRQHandler(void) {
if (MU_GetStatusFlags(MUA) & kMU_GenInt0Flag) {
MU_ClearStatusFlags(MUA, kMU_GenInt0Flag);
mp_sched_schedule_node(&rproc_notify_node, openamp_remoteproc_notified);
}
__DSB();
}

Wyświetl plik

@ -0,0 +1,73 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 Arduino SA
*
* 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.
*
* libmetal mimxrt port.
*/
#ifndef MICROPY_INCLUDED_MIMXRT_MPMETALPORT_H
#define MICROPY_INCLUDED_MIMXRT_MPMETALPORT_H
#include <stdlib.h>
#include "py/mphal.h"
#include "py/runtime.h"
#define METAL_HAVE_STDATOMIC_H 0
#define METAL_HAVE_FUTEX_H 0
#define METAL_MAX_DEVICE_REGIONS 2
// Set to 1 to enable the default log handler.
#define METAL_LOG_HANDLER_ENABLE 0
#define metal_cpu_yield()
// Shared memory config
#define METAL_SHM_NAME "OPENAMP_SHM"
// Note 1K must be reserved at the start of the openamp
// shared memory region, for the shared resource table.
#define METAL_RSC_ADDR ((void *)_openamp_shm_region_start)
#define METAL_RSC_SIZE (1024)
#define METAL_SHM_ADDR ((metal_phys_addr_t)(_openamp_shm_region_start + METAL_RSC_SIZE))
#define METAL_SHM_SIZE ((size_t)(_openamp_shm_region_end - _openamp_shm_region_start - METAL_RSC_SIZE))
#define METAL_MPU_REGION_BASE ((uint32_t)_openamp_shm_region_start)
#define METAL_MPU_REGION_SIZE (ARM_MPU_REGION_SIZE_64KB)
extern const char _openamp_shm_region_start[];
extern const char _openamp_shm_region_end[];
int metal_rproc_notify(void *priv, uint32_t id);
extern void openamp_remoteproc_notified(mp_sched_node_t *node);
static inline int __metal_sleep_usec(unsigned int usec) {
mp_hal_delay_us(usec);
return 0;
}
static inline void metal_generic_default_poll(void) {
MICROPY_EVENT_POLL_HOOK
}
#endif // MICROPY_INCLUDED_MIMXRT_METAL_PORT_H

Wyświetl plik

@ -0,0 +1,161 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 Arduino SA
*
* 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.
*
* modremoteproc mimxrt port.
*/
#include "py/obj.h"
#include "py/runtime.h"
#include "fsl_common.h"
#include "fsl_mu.h"
#include "metal/alloc.h"
#include "metal/errno.h"
#include "metal/io.h"
#include "metal/sys.h"
#include "metal/device.h"
#include "metal/utilities.h"
#include "extmod/modopenamp_remoteproc.h"
struct remoteproc *mp_openamp_remoteproc_init(struct remoteproc *rproc,
const struct remoteproc_ops *ops, void *arg) {
metal_log(METAL_LOG_DEBUG, "rproc_init()\n");
rproc->ops = ops;
rproc->state = RPROC_OFFLINE;
// Allocate the image store and save it in private data.
rproc->priv = mp_openamp_remoteproc_store_alloc();
return rproc;
}
void *mp_openamp_remoteproc_mmap(struct remoteproc *rproc, metal_phys_addr_t *pa,
metal_phys_addr_t *da, size_t size, unsigned int attribute,
struct metal_io_region **io) {
metal_log(METAL_LOG_DEBUG, "rproc_mmap(): pa 0x%p da 0x%p io 0x%p size %u\n", *pa, *da, *io, size);
struct remoteproc_mem *mem;
metal_phys_addr_t lpa = *pa;
metal_phys_addr_t lda = *da;
if (lda == METAL_BAD_PHYS) {
return NULL;
}
if (lpa == METAL_BAD_PHYS) {
lpa = lda;
}
if (lpa >= 0x1FFE0000 && lpa < 0x1FFFFFFF) {
// Map CM4 ITCM to CM7 address space.
lpa = 0x20200000 | (((uint32_t)lpa) & 0x1FFFF);
metal_log(METAL_LOG_DEBUG, "rproc_mmap(): remap 0x%p -> 0x%p\n", lda, lpa);
} else if (lpa >= 0x20000000 && lpa < 0x20020000) {
// Map CM4 DTCM to CM7 address space.
lpa = 0x20220000 | (((uint32_t)lpa) & 0x1FFFF);
metal_log(METAL_LOG_DEBUG, "rproc_mmap(): remap 0x%p -> 0x%p\n", lda, lpa);
}
mem = metal_allocate_memory(sizeof(*mem));
if (!mem) {
return NULL;
}
*io = metal_allocate_memory(sizeof(struct metal_io_region));
if (!*io) {
metal_free_memory(mem);
return NULL;
}
remoteproc_init_mem(mem, NULL, lpa, lda, size, *io);
metal_io_init(*io, (void *)lpa, &mem->pa, size,
sizeof(metal_phys_addr_t) << 3, attribute, NULL);
remoteproc_add_mem(rproc, mem);
*pa = lpa;
*da = lda;
return metal_io_phys_to_virt(*io, mem->pa);
}
int mp_openamp_remoteproc_start(struct remoteproc *rproc) {
metal_log(METAL_LOG_DEBUG, "rproc_start()\n");
if (SRC->SCR & SRC_SCR_BT_RELEASE_M4_MASK) {
// The CM4 core is already running.
metal_log(METAL_LOG_DEBUG, "rproc_start(): CM4 core is already booted.\n");
return -1;
}
// Flush M7 cache.
struct metal_list *node;
metal_list_for_each(&rproc->mems, node) {
struct remoteproc_mem *mem;
mem = metal_container_of(node, struct remoteproc_mem, node);
metal_log(METAL_LOG_DEBUG, "rproc_start() clean: pa 0x%p size %u\n", (uint32_t *)mem->pa, mem->size);
SCB_CleanDCache_by_Addr((uint32_t *)mem->pa, mem->size);
}
unsigned long offset = 0;
struct metal_io_region *io = remoteproc_get_io_with_da(rproc, rproc->bootaddr, &offset);
if (!io) {
return -1;
}
IOMUXC_LPSR_GPR->GPR0 = IOMUXC_LPSR_GPR_GPR0_CM4_INIT_VTOR_LOW(((uint32_t)io->virt) >> 3);
(void)IOMUXC_LPSR_GPR->GPR0;
IOMUXC_LPSR_GPR->GPR1 = IOMUXC_LPSR_GPR_GPR1_CM4_INIT_VTOR_HIGH(((uint32_t)io->virt) >> 16);
(void)IOMUXC_LPSR_GPR->GPR1;
SRC->CTRL_M4CORE = SRC_CTRL_M4CORE_SW_RESET_MASK;
SRC->SCR |= SRC_SCR_BT_RELEASE_M4_MASK;
return 0;
}
int mp_openamp_remoteproc_stop(struct remoteproc *rproc) {
metal_log(METAL_LOG_DEBUG, "rproc_stop()\n");
if (rproc->state == RPROC_RUNNING) {
NVIC_SystemReset();
}
return 0;
}
int mp_openamp_remoteproc_config(struct remoteproc *rproc, void *data) {
metal_log(METAL_LOG_DEBUG, "rproc_config()\n");
(void)rproc;
return 0;
}
void mp_openamp_remoteproc_remove(struct remoteproc *rproc) {
metal_log(METAL_LOG_DEBUG, "rproc_remove()\n");
(void)rproc;
}
int mp_openamp_remoteproc_shutdown(struct remoteproc *rproc) {
metal_log(METAL_LOG_DEBUG, "rproc_shutdown()\n");
if (rproc->state == RPROC_RUNNING) {
NVIC_SystemReset();
}
return 0;
}

Wyświetl plik

@ -9,8 +9,8 @@ BOARD ?= PCA10040
BOARD_DIR ?= boards/$(BOARD)
endif
ifeq ($(wildcard boards/$(BOARD)/.),)
$(error Invalid BOARD specified)
ifeq ($(wildcard $(BOARD_DIR)/.),)
$(error Invalid BOARD specified: $(BOARD_DIR))
endif
# If SoftDevice is selected, try to use that one.
@ -19,7 +19,7 @@ SD_LOWER = $(shell echo $(SD) | tr '[:upper:]' '[:lower:]')
# TODO: Verify that it is a valid target.
include boards/$(BOARD)/mpconfigboard.mk
include $(BOARD_DIR)/mpconfigboard.mk
ifeq ($(SD), )
# If the build directory is not given, make it reflect the board name.
@ -48,7 +48,7 @@ ifneq ($(LD_FILE),)
LD_FILES = $(LD_FILE)
endif
-include boards/$(BOARD)/modules/boardmodules.mk
-include $(BOARD_DIR)/modules/boardmodules.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h
@ -113,7 +113,7 @@ NRF_DEFINES += -D$(MCU_SUB_VARIANT_UPPER)
NRF_DEFINES += -DCONFIG_GPIO_AS_PINRESET
MAKE_PINS = boards/make-pins.py
BOARD_PINS = boards/$(BOARD)/pins.csv
BOARD_PINS = $(BOARD_DIR)/pins.csv
AF_FILE = $(MCU_VARIANT)_af.csv
PREFIX_FILE = boards/$(MCU_VARIANT)_prefix.c
GEN_PINS_SRC = $(BUILD)/pins_gen.c
@ -139,7 +139,7 @@ endif
CFLAGS += $(CFLAGS_MCU_$(MCU_SERIES))
CFLAGS += $(INC) -Wall -Werror -ansi -std=c11 -nostdlib $(COPT) $(NRF_DEFINES) $(CFLAGS_EXTRA)
CFLAGS += -fno-strict-aliasing
CFLAGS += -Iboards/$(BOARD)
CFLAGS += -I$(BOARD_DIR)
CFLAGS += -DNRF5_HAL_H='<$(MCU_VARIANT)_hal.h>'
LDFLAGS += $(CFLAGS)
@ -163,8 +163,6 @@ CFLAGS += -Os -DNDEBUG
LDFLAGS += -Os
endif
LIBS = \
ifeq ($(MCU_VARIANT), nrf52)
SRC_LIB_C += $(SRC_LIB_LIBM_C)
@ -481,7 +479,7 @@ $(OBJ): | $(HEADER_BUILD)/pins.h
# Use a pattern rule here so that make will only call make-pins.py once to make
# both pins_gen.c and pins.h
$(BUILD)/%_gen.c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
$(BUILD)/%_gen.c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h: $(BOARD_DIR)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
$(ECHO) "Create $@"
$(Q)$(PYTHON) $(MAKE_PINS) --board-csv $(BOARD_PINS) --af-csv $(AF_FILE) --prefix $(PREFIX_FILE) \
--output-source $(GEN_PINS_SRC) --output-header $(GEN_PINS_HDR) --output-af-const $(GEN_PINS_AF_CONST)

Wyświetl plik

@ -262,7 +262,7 @@ soft_reset:
led_state(1, 0);
#if MICROPY_VFS || MICROPY_MBFS || MICROPY_MODULE_FROZEN
ret = pyexec_file_if_exists("boot.py");
ret_code = pyexec_file_if_exists("boot.py");
#endif
#if MICROPY_HW_USB_CDC
@ -270,7 +270,7 @@ soft_reset:
#endif
#if MICROPY_VFS || MICROPY_MBFS || MICROPY_MODULE_FROZEN
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL && ret != 0) {
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL && ret_code != 0) {
pyexec_file_if_exists("main.py");
}
#endif

Wyświetl plik

@ -38,14 +38,14 @@
typedef struct _machine_adc_obj_t {
mp_obj_base_t base;
uint8_t id;
#if NRF51
uint8_t ain;
#endif
uint8_t id;
#if NRF51
uint8_t ain;
#endif
} machine_adc_obj_t;
static const machine_adc_obj_t machine_adc_obj[] = {
#if NRF51
#if NRF51
{{&machine_adc_type}, .id = 0, .ain = NRF_ADC_CONFIG_INPUT_0},
{{&machine_adc_type}, .id = 1, .ain = NRF_ADC_CONFIG_INPUT_1},
{{&machine_adc_type}, .id = 2, .ain = NRF_ADC_CONFIG_INPUT_2},
@ -54,7 +54,7 @@ static const machine_adc_obj_t machine_adc_obj[] = {
{{&machine_adc_type}, .id = 5, .ain = NRF_ADC_CONFIG_INPUT_5},
{{&machine_adc_type}, .id = 6, .ain = NRF_ADC_CONFIG_INPUT_6},
{{&machine_adc_type}, .id = 7, .ain = NRF_ADC_CONFIG_INPUT_7},
#else
#else
{{&machine_adc_type}, .id = 0},
{{&machine_adc_type}, .id = 1},
{{&machine_adc_type}, .id = 2},
@ -63,14 +63,14 @@ static const machine_adc_obj_t machine_adc_obj[] = {
{{&machine_adc_type}, .id = 5},
{{&machine_adc_type}, .id = 6},
{{&machine_adc_type}, .id = 7},
#endif
#endif
};
void adc_init0(void) {
#if defined(NRF52_SERIES)
#if defined(NRF52_SERIES)
const uint8_t interrupt_priority = 6;
nrfx_saadc_init(interrupt_priority);
#endif
#endif
}
static int adc_find(mp_obj_t id) {
@ -124,49 +124,49 @@ static mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_args
int adc_id = adc_find(args[ARG_id].u_obj);
const machine_adc_obj_t *self = &machine_adc_obj[adc_id];
#if defined(NRF52_SERIES)
#if defined(NRF52_SERIES)
const nrfx_saadc_channel_t config = { \
.channel_config =
{
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
.gain = NRF_SAADC_GAIN1_4,
.reference = NRF_SAADC_REFERENCE_VDD4,
.acq_time = NRF_SAADC_ACQTIME_3US,
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
.burst = NRF_SAADC_BURST_DISABLED,
.gain = NRF_SAADC_GAIN1_4,
.reference = NRF_SAADC_REFERENCE_VDD4,
.acq_time = NRF_SAADC_ACQTIME_3US,
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
.burst = NRF_SAADC_BURST_DISABLED,
},
.pin_p = (nrf_saadc_input_t)(1 + self->id), // pin_p=0 is AIN0, pin_p=8 is AIN7
.pin_n = NRF_SAADC_INPUT_DISABLED,
.channel_index = self->id,
.pin_p = (nrf_saadc_input_t)(1 + self->id), // pin_p=0 is AIN0, pin_p=8 is AIN7
.pin_n = NRF_SAADC_INPUT_DISABLED,
.channel_index = self->id,
};
nrfx_saadc_channels_config(&config, 1);
#endif
#endif
return MP_OBJ_FROM_PTR(self);
}
int16_t machine_adc_value_read(machine_adc_obj_t * adc_obj) {
int16_t machine_adc_value_read(machine_adc_obj_t *adc_obj) {
#if NRF51
#if NRF51
nrf_adc_value_t value = 0;
nrfx_adc_channel_t channel_config = {
.config.resolution = NRF_ADC_CONFIG_RES_8BIT,
.config.input = NRF_ADC_CONFIG_SCALING_INPUT_TWO_THIRDS,
.config.reference = NRF_ADC_CONFIG_REF_VBG,
.config.input = adc_obj->ain,
.config.extref = ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos // Currently not defined in nrfx/hal.
.config.input = NRF_ADC_CONFIG_SCALING_INPUT_TWO_THIRDS,
.config.reference = NRF_ADC_CONFIG_REF_VBG,
.config.input = adc_obj->ain,
.config.extref = ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos // Currently not defined in nrfx/hal.
};
nrfx_adc_sample_convert(&channel_config, &value);
#else // NRF52
#else // NRF52
nrf_saadc_value_t value = 0;
nrfx_saadc_simple_mode_set((1 << adc_obj->id), NRF_SAADC_RESOLUTION_8BIT, NRF_SAADC_INPUT_DISABLED, NULL);
nrfx_saadc_buffer_set(&value, 1);
nrfx_saadc_mode_trigger();
#endif
#endif
return value;
}
@ -209,10 +209,9 @@ static MP_DEFINE_CONST_FUN_OBJ_1(mp_machine_adc_value_obj, machine_adc_value);
#define DIODE_VOLT_DROP_MILLIVOLT (270) // Voltage drop over diode.
#define BATTERY_MILLIVOLT(VALUE) \
((((VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLT) / 255) * ADC_PRE_SCALING_MULTIPLIER)
((((VALUE)*ADC_REF_VOLTAGE_IN_MILLIVOLT) / 255) * ADC_PRE_SCALING_MULTIPLIER)
static uint8_t battery_level_in_percent(const uint16_t mvolts)
{
static uint8_t battery_level_in_percent(const uint16_t mvolts) {
uint8_t battery_level;
if (mvolts >= 3000) {
@ -236,19 +235,19 @@ static uint8_t battery_level_in_percent(const uint16_t mvolts)
/// Get battery level in percentage.
mp_obj_t machine_adc_battery_level(void) {
#if NRF51
#if NRF51
nrf_adc_value_t value = 0;
nrfx_adc_channel_t channel_config = {
.config.resolution = NRF_ADC_CONFIG_RES_8BIT,
.config.input = NRF_ADC_CONFIG_SCALING_SUPPLY_ONE_THIRD,
.config.reference = NRF_ADC_CONFIG_REF_VBG,
.config.input = NRF_ADC_CONFIG_INPUT_DISABLED,
.config.extref = ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos // Currently not defined in nrfx/hal.
.config.input = NRF_ADC_CONFIG_SCALING_SUPPLY_ONE_THIRD,
.config.reference = NRF_ADC_CONFIG_REF_VBG,
.config.input = NRF_ADC_CONFIG_INPUT_DISABLED,
.config.extref = ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos // Currently not defined in nrfx/hal.
};
nrfx_adc_sample_convert(&channel_config, &value);
#else // NRF52
#else // NRF52
nrf_saadc_value_t value = 0;
const nrfx_saadc_channel_t config = { \
@ -256,22 +255,22 @@ mp_obj_t machine_adc_battery_level(void) {
{
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
.gain = NRF_SAADC_GAIN1_6,
.reference = NRF_SAADC_REFERENCE_INTERNAL,
.acq_time = NRF_SAADC_ACQTIME_3US,
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
.burst = NRF_SAADC_BURST_DISABLED,
.gain = NRF_SAADC_GAIN1_6,
.reference = NRF_SAADC_REFERENCE_INTERNAL,
.acq_time = NRF_SAADC_ACQTIME_3US,
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
.burst = NRF_SAADC_BURST_DISABLED,
},
.pin_p = NRF_SAADC_INPUT_VDD,
.pin_n = NRF_SAADC_INPUT_DISABLED,
.channel_index = 0,
.pin_p = NRF_SAADC_INPUT_VDD,
.pin_n = NRF_SAADC_INPUT_DISABLED,
.channel_index = 0,
};
nrfx_saadc_channels_config(&config, 1);
nrfx_saadc_simple_mode_set((1 << 0), NRF_SAADC_RESOLUTION_8BIT, NRF_SAADC_INPUT_DISABLED, NULL);
nrfx_saadc_buffer_set(&value, 1);
nrfx_saadc_mode_trigger();
#endif
#endif
uint16_t batt_lvl_in_milli_volts = BATTERY_MILLIVOLT(value) + DIODE_VOLT_DROP_MILLIVOLT;
uint16_t batt_in_percent = battery_level_in_percent(batt_lvl_in_milli_volts);

Wyświetl plik

@ -31,6 +31,6 @@ typedef struct _machine_adc_obj_t machine_adc_obj_t;
void adc_init0(void);
int16_t machine_adc_value_read(machine_adc_obj_t * adc_obj);
int16_t machine_adc_value_read(machine_adc_obj_t *adc_obj);
#endif // ADC_H__

Wyświetl plik

@ -68,7 +68,7 @@
typedef struct _machine_hard_i2c_obj_t {
mp_obj_base_t base;
nrfx_twi_t p_twi; // Driver instance
nrfx_twi_t p_twi; // Driver instance
} machine_hard_i2c_obj_t;
static const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = {
@ -159,8 +159,7 @@ int machine_hard_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size
if (err_code != NRFX_SUCCESS) {
if (err_code == NRFX_ERROR_DRV_TWI_ERR_ANACK) {
return -MP_ENODEV;
}
else if (err_code == NRFX_ERROR_DRV_TWI_ERR_DNACK) {
} else if (err_code == NRFX_ERROR_DRV_TWI_ERR_DNACK) {
return -MP_EIO;
}
return -MP_ETIMEDOUT;

Wyświetl plik

@ -116,16 +116,16 @@ void machine_init(void) {
reset_cause = PYB_RESET_LOCKUP;
} else if (state & POWER_RESETREAS_OFF_Msk) {
reset_cause = PYB_RESET_POWER_ON;
#if !defined(NRF9160_XXAA)
#if !defined(NRF9160_XXAA)
} else if (state & POWER_RESETREAS_LPCOMP_Msk) {
reset_cause = PYB_RESET_LPCOMP;
#endif
#endif
} else if (state & POWER_RESETREAS_DIF_Msk) {
reset_cause = PYB_RESET_DIF;
#if defined(NRF52_SERIES)
#if defined(NRF52_SERIES)
} else if (state & POWER_RESETREAS_NFC_Msk) {
reset_cause = PYB_RESET_NFC;
#endif
#endif
}
// clear reset reason
@ -216,22 +216,22 @@ static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) {
}
static mp_obj_t machine_enable_irq(void) {
#ifndef BLUETOOTH_SD
#ifndef BLUETOOTH_SD
__enable_irq();
#else
#else
#endif
#endif
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(machine_enable_irq_obj, machine_enable_irq);
// Resets the board in a manner similar to pushing the external RESET button.
static mp_obj_t machine_disable_irq(void) {
#ifndef BLUETOOTH_SD
#ifndef BLUETOOTH_SD
__disable_irq();
#else
#else
#endif
#endif
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq);

Wyświetl plik

@ -33,6 +33,7 @@
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "py/gc.h"
#include "pin.h"
#include "nrf_gpio.h"
#include "nrfx_gpiote.h"
@ -234,9 +235,9 @@ static void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
}
mp_printf(print, "Pin(%d, mode=%s, pull=%s)",
self->pin,
(nrf_gpio_pin_dir_get(self->pin) == NRF_GPIO_PIN_DIR_OUTPUT) ? "OUT" : "IN",
pull);
self->pin,
(nrf_gpio_pin_dir_get(self->pin) == NRF_GPIO_PIN_DIR_OUTPUT) ? "OUT" : "IN",
pull);
}
static mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
@ -375,11 +376,11 @@ static mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, con
if (mode == NRF_GPIO_PIN_DIR_OUTPUT || mode == NRF_GPIO_PIN_DIR_INPUT) {
nrf_gpio_cfg(self->pin,
mode,
input,
pull,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
mode,
input,
pull,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
} else {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("invalid pin mode: %d"), mode);
}
@ -496,9 +497,31 @@ static MP_DEFINE_CONST_FUN_OBJ_1(pin_af_obj, pin_af);
static void pin_common_irq_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
mp_obj_t pin_handler = MP_STATE_PORT(pin_irq_handlers)[pin];
mp_obj_t pin_number = MP_OBJ_NEW_SMALL_INT(pin);
const pin_obj_t *pin_obj = pin_find(pin_number);
const pin_obj_t *pin_obj = pin_find(pin_number);
mp_call_function_1(pin_handler, (mp_obj_t)pin_obj);
if (pin_handler != mp_const_none) {
#if MICROPY_ENABLE_SCHEDULER
mp_sched_lock();
#endif
// When executing code within a handler we must lock the GC to prevent
// any memory allocations. We must also catch any exceptions.
gc_lock();
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_call_function_1(pin_handler, (mp_obj_t)pin_obj);
nlr_pop();
} else {
// Uncaught exception; disable the callback so it doesn't run again.
MP_STATE_PORT(pin_irq_handlers)[pin] = mp_const_none;
nrfx_gpiote_in_uninit(pin);
mp_printf(MICROPY_ERROR_PRINTER, "uncaught exception in interrupt handler for Pin('%q')\n", pin_obj->name);
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
}
gc_unlock();
#if MICROPY_ENABLE_SCHEDULER
mp_sched_unlock();
#endif
}
}
static mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
@ -591,7 +614,7 @@ static const mp_rom_map_elem_t pin_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_AF_OD), MP_ROM_INT(GPIO_MODE_AF_OD) },
{ MP_ROM_QSTR(MP_QSTR_PULL_NONE), MP_ROM_INT(GPIO_NOPULL) },
*/
#include "genhdr/pins_af_const.h"
#include "genhdr/pins_af_const.h"
};
static MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table);

Wyświetl plik

@ -34,43 +34,43 @@
#include "py/obj.h"
typedef struct {
mp_obj_base_t base;
qstr name;
uint8_t idx;
uint8_t fn;
uint8_t unit;
uint8_t type;
mp_obj_base_t base;
qstr name;
uint8_t idx;
uint8_t fn;
uint8_t unit;
uint8_t type;
union {
void *reg;
union {
void *reg;
PIN_DEFS_PORT_AF_UNION
};
PIN_DEFS_PORT_AF_UNION
};
} pin_af_obj_t;
typedef struct {
mp_obj_base_t base;
qstr name;
uint32_t pin : 8;
uint32_t num_af : 4;
uint32_t adc_channel : 5; // Some ARM processors use 32 bits/PORT
uint32_t adc_num : 3; // 1 bit per ADC
const pin_af_obj_t *af;
uint32_t pull;
mp_obj_base_t base;
qstr name;
uint32_t pin : 8;
uint32_t num_af : 4;
uint32_t adc_channel : 5; // Some ARM processors use 32 bits/PORT
uint32_t adc_num : 3; // 1 bit per ADC
const pin_af_obj_t *af;
uint32_t pull;
} pin_obj_t;
extern const mp_obj_type_t pin_type;
extern const mp_obj_type_t pin_af_type;
typedef struct {
const char *name;
const pin_obj_t *pin;
const char *name;
const pin_obj_t *pin;
} pin_named_pin_t;
extern const pin_named_pin_t pin_board_pins[];
extern const pin_named_pin_t pin_cpu_pins[];
//extern pin_map_obj_t pin_map_obj;
// extern pin_map_obj_t pin_map_obj;
typedef struct {
mp_obj_base_t base;

Wyświetl plik

@ -233,6 +233,11 @@ static mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
self->p_config->mode[pwm_channel] = MODE_HIGH_LOW;
self->p_config->defer_start = false;
// Allocate the device if it was not used before.
if (hard_configs[pwm_id].active == FREE) {
hard_configs[pwm_id].active = STOPPED;
}
// start the PWM running for this channel
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);

Wyświetl plik

@ -27,6 +27,7 @@
#include "py/nlr.h"
#include "py/runtime.h"
#include "mphalport.h"
#include "rtcounter.h"
#include "nrfx_rtc.h"
#include "nrf_clock.h"
@ -49,18 +50,18 @@ typedef struct {
// Non-volatile part of the RTCounter object.
typedef struct _machine_rtc_obj_t {
mp_obj_base_t base;
const nrfx_rtc_t * p_rtc; // Driver instance
nrfx_rtc_handler_t handler; // interrupt callback
machine_rtc_config_t * config; // pointer to volatile part
mp_obj_base_t base;
const nrfx_rtc_t *p_rtc; // Driver instance
nrfx_rtc_handler_t handler; // interrupt callback
machine_rtc_config_t *config; // pointer to volatile part
} machine_rtc_obj_t;
static const nrfx_rtc_t machine_rtc_instances[] = {
NRFX_RTC_INSTANCE(0),
NRFX_RTC_INSTANCE(1),
#if defined(NRF52_SERIES)
#if defined(NRF52_SERIES)
NRFX_RTC_INSTANCE(2),
#endif
#endif
};
static machine_rtc_config_t configs[MP_ARRAY_SIZE(machine_rtc_instances)];
@ -72,15 +73,15 @@ static void interrupt_handler2(nrfx_rtc_int_type_t int_type);
#endif
static const machine_rtc_obj_t machine_rtc_obj[] = {
{{&machine_rtcounter_type}, .p_rtc = &machine_rtc_instances[0], .handler=interrupt_handler0, .config=&configs[0]},
{{&machine_rtcounter_type}, .p_rtc = &machine_rtc_instances[1], .handler=interrupt_handler1, .config=&configs[1]},
#if defined(NRF52_SERIES)
{{&machine_rtcounter_type}, .p_rtc = &machine_rtc_instances[2], .handler=interrupt_handler2, .config=&configs[2]},
#endif
{{&machine_rtcounter_type}, .p_rtc = &machine_rtc_instances[0], .handler = interrupt_handler0, .config = &configs[0]},
{{&machine_rtcounter_type}, .p_rtc = &machine_rtc_instances[1], .handler = interrupt_handler1, .config = &configs[1]},
#if defined(NRF52_SERIES)
{{&machine_rtcounter_type}, .p_rtc = &machine_rtc_instances[2], .handler = interrupt_handler2, .config = &configs[2]},
#endif
};
static void interrupt_handler(size_t instance_id) {
const machine_rtc_obj_t * self = &machine_rtc_obj[instance_id];
const machine_rtc_obj_t *self = &machine_rtc_obj[instance_id];
machine_rtc_config_t *config = self->config;
if (config->callback != NULL) {
mp_call_function_1((mp_obj_t)config->callback, (mp_obj_t)self);
@ -128,8 +129,8 @@ static void rtc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
/* MicroPython bindings for machine API */
const nrfx_rtc_config_t machine_rtc_config = {
.prescaler = RTC_FREQ_TO_PRESCALER(RTC_FREQUENCY),
.reliable = 0,
.prescaler = RTC_FREQ_TO_PRESCALER(RTC_FREQUENCY),
.reliable = 0,
.tick_latency = 0, // ignored when reliable == 0
#ifdef NRF51
.interrupt_priority = 3,
@ -161,7 +162,7 @@ static mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s
#endif
// const and non-const part of the RTC object.
const machine_rtc_obj_t * self = &machine_rtc_obj[rtc_id];
const machine_rtc_obj_t *self = &machine_rtc_obj[rtc_id];
machine_rtc_config_t *config = self->config;
if (args[ARG_callback].u_obj == mp_const_none) {
@ -182,9 +183,7 @@ static mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s
}
// Start the low-frequency clock (if it hasn't been started already)
if (!nrf_clock_lf_is_running(NRF_CLOCK)) {
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
}
mp_nrf_start_lfclk();
// Make sure it's uninitialized.
nrfx_rtc_uninit(self->p_rtc);
@ -202,7 +201,7 @@ static mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s
/// in the configured frequency has been reached.
///
static mp_obj_t machine_rtc_start(mp_obj_t self_in) {
machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in);
machine_rtc_obj_t *self = MP_OBJ_TO_PTR(self_in);
nrfx_rtc_enable(self->p_rtc);
@ -214,7 +213,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_start_obj, machine_rtc_start);
/// Stop the RTCounter.
///
static mp_obj_t machine_rtc_stop(mp_obj_t self_in) {
machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in);
machine_rtc_obj_t *self = MP_OBJ_TO_PTR(self_in);
nrfx_rtc_disable(self->p_rtc);
@ -227,7 +226,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_stop_obj, machine_rtc_stop);
/// with the current prescaler (2^24 / 8 = 2097152 seconds).
///
static mp_obj_t machine_rtc_counter(mp_obj_t self_in) {
machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in);
machine_rtc_obj_t *self = MP_OBJ_TO_PTR(self_in);
uint32_t counter = nrfx_rtc_counter_get(self->p_rtc);
@ -239,7 +238,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_counter_obj, machine_rtc_counter);
/// Free resources associated with this RTC.
///
static mp_obj_t machine_rtc_deinit(mp_obj_t self_in) {
machine_rtc_obj_t * self = MP_OBJ_TO_PTR(self_in);
machine_rtc_obj_t *self = MP_OBJ_TO_PTR(self_in);
nrfx_rtc_uninit(self->p_rtc);

Wyświetl plik

@ -102,7 +102,7 @@ static mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
mp_raise_ValueError(MP_ERROR_TEXT("Pin number >31"));
}
machine_pwm_obj_t *self = mp_obj_malloc(machine_pwm_obj_t, &machine_pwm_type);;
machine_pwm_obj_t *self = mp_obj_malloc(machine_pwm_obj_t, &machine_pwm_type);
self->defer_start = false;
self->pwm_pin = pwm_pin;
self->duty_mode = DUTY_NOT_SET;
@ -197,7 +197,7 @@ static void machine_soft_pwm_start(machine_pwm_obj_t *self) {
duty_width = self->duty * DUTY_FULL_SCALE / 100;
} else if (self->duty_mode == DUTY_U16) {
duty_width = self->duty * DUTY_FULL_SCALE / 65536;
}if (self->duty_mode == DUTY_NS) {
} else if (self->duty_mode == DUTY_NS) {
duty_width = (uint64_t)self->duty * self->freq * DUTY_FULL_SCALE / 1000000000ULL;
}
pwm_set_duty_cycle(self->pwm_pin, duty_width);

Wyświetl plik

@ -98,20 +98,20 @@
#endif // NRFX_SPIM_ENABLED
typedef struct _machine_hard_spi_obj_t {
mp_obj_base_t base;
const nrfx_spi_t * p_spi; // Driver instance
nrfx_spi_config_t * p_config; // pointer to volatile part
mp_obj_base_t base;
const nrfx_spi_t *p_spi; // Driver instance
nrfx_spi_config_t *p_config; // pointer to volatile part
} machine_hard_spi_obj_t;
static const nrfx_spi_t machine_spi_instances[] = {
NRFX_SPI_INSTANCE(0),
NRFX_SPI_INSTANCE(1),
#if defined(NRF52_SERIES)
#if defined(NRF52_SERIES)
NRFX_SPI_INSTANCE(2),
#if defined(NRF52840_XXAA) && NRFX_SPIM_ENABLED
#if defined(NRF52840_XXAA) && NRFX_SPIM_ENABLED
NRFX_SPI_INSTANCE(3),
#endif // NRF52840_XXAA && NRFX_SPIM_ENABLED
#endif // NRF52_SERIES
#endif // NRF52840_XXAA && NRFX_SPIM_ENABLED
#endif // NRF52_SERIES
};
static nrfx_spi_config_t configs[MP_ARRAY_SIZE(machine_spi_instances)];
@ -119,12 +119,12 @@ static nrfx_spi_config_t configs[MP_ARRAY_SIZE(machine_spi_instances)];
static const machine_hard_spi_obj_t machine_hard_spi_obj[] = {
{{&machine_spi_type}, .p_spi = &machine_spi_instances[0], .p_config = &configs[0]},
{{&machine_spi_type}, .p_spi = &machine_spi_instances[1], .p_config = &configs[1]},
#if defined(NRF52_SERIES)
#if defined(NRF52_SERIES)
{{&machine_spi_type}, .p_spi = &machine_spi_instances[2], .p_config = &configs[2]},
#if defined(NRF52840_XXAA) && NRFX_SPIM_ENABLED
#if defined(NRF52840_XXAA) && NRFX_SPIM_ENABLED
{{&machine_spi_type}, .p_spi = &machine_spi_instances[3], .p_config = &configs[3]},
#endif // NRF52840_XXAA && NRFX_SPIM_ENABLED
#endif // NRF52_SERIES
#endif // NRF52840_XXAA && NRFX_SPIM_ENABLED
#endif // NRF52_SERIES
};
void spi_init0(void) {
@ -151,12 +151,12 @@ static int spi_find(mp_obj_t id) {
}
}
void spi_transfer(const machine_hard_spi_obj_t * self, size_t len, const void * src, void * dest) {
void spi_transfer(const machine_hard_spi_obj_t *self, size_t len, const void *src, void *dest) {
nrfx_spi_xfer_desc_t xfer_desc = {
.p_tx_buffer = src,
.tx_length = len,
.tx_length = len,
.p_rx_buffer = dest,
.rx_length = len
.rx_length = len
};
nrfx_spi_xfer(self->p_spi, &xfer_desc, 0);
@ -220,11 +220,11 @@ static mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_ar
&& args[ARG_NEW_mosi].u_obj != MP_OBJ_NULL
&& args[ARG_NEW_miso].u_obj != MP_OBJ_NULL) {
self->p_config->sck_pin = mp_hal_get_pin_obj(args[ARG_NEW_sck].u_obj)->pin;
self->p_config->sck_pin = mp_hal_get_pin_obj(args[ARG_NEW_sck].u_obj)->pin;
self->p_config->mosi_pin = mp_hal_get_pin_obj(args[ARG_NEW_mosi].u_obj)->pin;
self->p_config->miso_pin = mp_hal_get_pin_obj(args[ARG_NEW_miso].u_obj)->pin;
} else {
self->p_config->sck_pin = MICROPY_HW_SPI0_SCK;
self->p_config->sck_pin = MICROPY_HW_SPI0_SCK;
self->p_config->mosi_pin = MICROPY_HW_SPI0_MOSI;
self->p_config->miso_pin = MICROPY_HW_SPI0_MISO;
}
@ -232,11 +232,11 @@ static mp_obj_t machine_hard_spi_make_new(const mp_obj_type_t *type, size_t n_ar
// Manually trigger slave select from upper layer.
self->p_config->ss_pin = NRFX_SPI_PIN_NOT_USED;
#ifdef NRF51
#ifdef NRF51
self->p_config->irq_priority = 3;
#else
#else
self->p_config->irq_priority = 6;
#endif
#endif
machine_hard_spi_init_helper(self, &args[1]); // Skip instance id param.
@ -260,18 +260,18 @@ static void machine_hard_spi_init_helper(const machine_hard_spi_obj_t *self, mp_
self->p_config->frequency = NRF_SPI_FREQ_4M;
} else if (baudrate <= 8000000) {
self->p_config->frequency = NRF_SPI_FREQ_8M;
#if defined(NRF52840_XXAA) && NRFX_SPIM_ENABLED
#if defined(NRF52840_XXAA) && NRFX_SPIM_ENABLED
} else if (baudrate <= 16000000) {
self->p_config->frequency = NRF_SPIM_FREQ_16M;
} else if (baudrate <= 32000000) {
self->p_config->frequency = NRF_SPIM_FREQ_32M;
#endif // NRF52840_XXAA && NRFX_SPIM_ENABLED
#endif // NRF52840_XXAA && NRFX_SPIM_ENABLED
} else { // Default
self->p_config->frequency = NRF_SPI_FREQ_1M;
}
// Active high
if (args[ARG_INIT_polarity].u_int == 0) {
// Active high
if (args[ARG_INIT_phase].u_int == 0) {
// First clock edge
self->p_config->mode = NRF_SPI_MODE_0;
@ -279,8 +279,8 @@ static void machine_hard_spi_init_helper(const machine_hard_spi_obj_t *self, mp_
// Second clock edge
self->p_config->mode = NRF_SPI_MODE_1;
}
// Active low
} else {
// Active low
if (args[ARG_INIT_phase].u_int == 0) {
// First clock edge
self->p_config->mode = NRF_SPI_MODE_2;
@ -290,7 +290,7 @@ static void machine_hard_spi_init_helper(const machine_hard_spi_obj_t *self, mp_
}
}
self->p_config->orc = 0xFF; // Overrun character
self->p_config->orc = 0xFF; // Overrun character
self->p_config->bit_order = (args[ARG_INIT_firstbit].u_int == 0) ? NRF_SPI_BIT_ORDER_MSB_FIRST : NRF_SPI_BIT_ORDER_LSB_FIRST;
// Set context to this instance of SPI
@ -327,7 +327,7 @@ static void machine_hard_spi_deinit(mp_obj_base_t *self_in) {
}
static void machine_hard_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
const machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t*)self_in;
const machine_hard_spi_obj_t *self = (machine_hard_spi_obj_t *)self_in;
spi_transfer(self, len, src, dest);
}

Wyświetl plik

@ -29,7 +29,7 @@
typedef struct _machine_hard_spi_obj_t machine_hard_spi_obj_t;
void spi_init0(void);
void spi_transfer(const machine_hard_spi_obj_t * self,
size_t len,
const void * src,
void * dest);
void spi_transfer(const machine_hard_spi_obj_t *self,
size_t len,
const void *src,
void *dest);

Wyświetl plik

@ -91,13 +91,13 @@ int32_t temp_read(void) {
/// Get temperature.
static mp_obj_t machine_temp_read(mp_uint_t n_args, const mp_obj_t *args) {
#if BLUETOOTH_SD
#if BLUETOOTH_SD
if (BLUETOOTH_STACK_ENABLED() == 1) {
int32_t temp;
(void)sd_temp_get(&temp);
return MP_OBJ_NEW_SMALL_INT(temp / 4); // resolution of 0.25 degree celsius
}
#endif // BLUETOOTH_SD
#endif // BLUETOOTH_SD
return MP_OBJ_NEW_SMALL_INT(temp_read());
}

Wyświetl plik

@ -37,32 +37,32 @@ enum {
};
typedef struct _machine_timer_obj_t {
mp_obj_base_t base;
nrfx_timer_t p_instance;
mp_obj_base_t base;
nrfx_timer_t p_instance;
} machine_timer_obj_t;
static mp_obj_t machine_timer_callbacks[] = {
NULL,
NULL,
NULL,
#if defined(NRF52_SERIES)
#if defined(NRF52_SERIES)
NULL,
NULL,
#endif
#endif
};
static const machine_timer_obj_t machine_timer_obj[] = {
{{&machine_timer_type}, NRFX_TIMER_INSTANCE(0)},
#if MICROPY_PY_MACHINE_SOFT_PWM
#if MICROPY_PY_MACHINE_SOFT_PWM
{ },
#else
#else
{{&machine_timer_type}, NRFX_TIMER_INSTANCE(1)},
#endif
#endif
{{&machine_timer_type}, NRFX_TIMER_INSTANCE(2)},
#if defined(NRF52_SERIES)
#if defined(NRF52_SERIES)
{{&machine_timer_type}, NRFX_TIMER_INSTANCE(3)},
{{&machine_timer_type}, NRFX_TIMER_INSTANCE(4)},
#endif
#endif
};
void timer_init0(void) {
@ -112,19 +112,19 @@ static mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args,
// get static peripheral object
int timer_id = timer_find(args[ARG_id].u_obj);
#if BLUETOOTH_SD
#if BLUETOOTH_SD
if (timer_id == 0) {
mp_raise_ValueError(MP_ERROR_TEXT("Timer reserved by Bluetooth LE stack"));
}
#endif
#endif
#if MICROPY_PY_MACHINE_SOFT_PWM
#if MICROPY_PY_MACHINE_SOFT_PWM
if (timer_id == 1) {
mp_raise_ValueError(MP_ERROR_TEXT("Timer reserved by ticker driver"));
}
#endif
#endif
machine_timer_obj_t *self = (machine_timer_obj_t*)&machine_timer_obj[timer_id];
machine_timer_obj_t *self = (machine_timer_obj_t *)&machine_timer_obj[timer_id];
if (mp_obj_is_fun(args[ARG_callback].u_obj)) {
machine_timer_callbacks[timer_id] = args[ARG_callback].u_obj;
@ -163,11 +163,11 @@ static mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args,
((args[ARG_mode].u_int == TIMER_MODE_ONESHOT) ? NRF_TIMER_SHORT_COMPARE0_STOP_MASK : 0);
bool enable_interrupts = true;
nrfx_timer_extended_compare(
&self->p_instance,
NRF_TIMER_CC_CHANNEL0,
args[ARG_period].u_int,
short_mask,
enable_interrupts);
&self->p_instance,
NRF_TIMER_CC_CHANNEL0,
args[ARG_period].u_int,
short_mask,
enable_interrupts);
return MP_OBJ_FROM_PTR(self);
}
@ -176,7 +176,7 @@ static mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args,
/// Return counter value, which is currently in us.
///
static mp_obj_t machine_timer_period(mp_obj_t self_in) {
machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in);
machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
uint32_t period = nrfx_timer_capture(&self->p_instance, NRF_TIMER_CC_CHANNEL1);
@ -188,7 +188,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_period_obj, machine_timer_period)
/// Start the timer.
///
static mp_obj_t machine_timer_start(mp_obj_t self_in) {
machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in);
machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
nrfx_timer_enable(&self->p_instance);
@ -200,7 +200,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_start_obj, machine_timer_start);
/// Stop the timer.
///
static mp_obj_t machine_timer_stop(mp_obj_t self_in) {
machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in);
machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
nrfx_timer_disable(&self->p_instance);
@ -212,7 +212,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_stop_obj, machine_timer_stop);
/// Free resources associated with the timer.
///
static mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
machine_timer_obj_t * self = MP_OBJ_TO_PTR(self_in);
machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
nrfx_timer_uninit(&self->p_instance);

Wyświetl plik

@ -88,8 +88,8 @@ typedef struct _machine_uart_buf_t {
#endif
typedef struct _machine_uart_obj_t {
mp_obj_base_t base;
const nrfx_uart_t * p_uart; // Driver instance
mp_obj_base_t base;
const nrfx_uart_t *p_uart; // Driver instance
machine_uart_buf_t buf;
uint16_t timeout; // timeout waiting for first char (in ms)
uint16_t timeout_char; // timeout waiting between chars (in ms)
@ -206,19 +206,17 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
nrfx_uart_config_t config;
// flow control
#if MICROPY_HW_UART1_HWFC
#if MICROPY_HW_UART1_HWFC
config.hal_cfg.hwfc = NRF_UART_HWFC_ENABLED;
#else
#else
config.hal_cfg.hwfc = NRF_UART_HWFC_DISABLED;
#endif
#endif
config.hal_cfg.parity = NRF_UART_PARITY_EXCLUDED;
#if (BLUETOOTH_SD == 100)
config.interrupt_priority = 3;
#else
config.interrupt_priority = 6;
#endif
// Higher priority than pin interrupts, otherwise printing exceptions from
// interrupt handlers gets stuck.
config.interrupt_priority = NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY - 1;
// These baudrates are not supported, it seems.
if (args[ARG_baudrate].u_int < 1200 || args[ARG_baudrate].u_int > 1000000) {
@ -239,10 +237,10 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
config.pseltxd = MICROPY_HW_UART1_TX;
config.pselrxd = MICROPY_HW_UART1_RX;
#if MICROPY_HW_UART1_HWFC
#if MICROPY_HW_UART1_HWFC
config.pselrts = MICROPY_HW_UART1_RTS;
config.pselcts = MICROPY_HW_UART1_CTS;
#endif
#endif
self->timeout = args[ARG_timeout].u_int;
self->timeout_char = args[ARG_timeout_char].u_int;
@ -259,9 +257,9 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
nrfx_uart_init(self->p_uart, &config, uart_event_handler);
nrfx_uart_rx(self->p_uart, &self->buf.rx_buf[0], 1);
#if NRFX_UART_ENABLED
#if NRFX_UART_ENABLED
nrfx_uart_rx_enable(self->p_uart);
#endif
#endif
return MP_OBJ_FROM_PTR(self);
}

Wyświetl plik

@ -59,6 +59,12 @@
// options to control how MicroPython is built
// Due to the use of LTO and the unknown distance between nlr.o and nlrthumb.o code,
// MCUs using the Thumb 1 instruction set must enable this NLR long jump feature.
#if defined(NRF51822)
#define MICROPY_NLR_THUMB_USE_LONG_JUMP (1)
#endif
#ifndef MICROPY_VFS
#define MICROPY_VFS (CORE_FEAT)
#endif

Wyświetl plik

@ -40,6 +40,36 @@
#include "nrf_clock.h"
#endif
#if !defined(USE_WORKAROUND_FOR_ANOMALY_132) && \
(defined(NRF52832_XXAA) || defined(NRF52832_XXAB))
// ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop.
#define USE_WORKAROUND_FOR_ANOMALY_132 1
#endif
#if USE_WORKAROUND_FOR_ANOMALY_132
#include "soc/nrfx_coredep.h"
#endif
void mp_nrf_start_lfclk(void) {
if (!nrf_clock_lf_start_task_status_get(NRF_CLOCK)) {
// Check if the clock was recently stopped but is still running.
#if USE_WORKAROUND_FOR_ANOMALY_132
bool was_running = nrf_clock_lf_is_running(NRF_CLOCK);
// If so, wait for it to stop. This ensures that the delay for anomaly 132 workaround does
// not land us in the middle of the forbidden interval.
while (nrf_clock_lf_is_running(NRF_CLOCK)) {
}
// If the clock just stopped, we can start it again right away as we are certainly before
// the forbidden 66-138us interval. Otherwise, apply a delay of 138us to make sure we are
// after the interval.
if (!was_running) {
nrfx_coredep_delay_us(138);
}
#endif
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
}
}
#if MICROPY_PY_TIME_TICKS
// Use RTC1 for time ticks generation (ms and us) with 32kHz tick resolution
@ -99,9 +129,7 @@ static void rtc_irq_time(nrfx_rtc_int_type_t event) {
void rtc1_init_time_ticks(void) {
// Start the low-frequency clock (if it hasn't been started already)
if (!nrf_clock_lf_is_running(NRF_CLOCK)) {
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
}
mp_nrf_start_lfclk();
// Uninitialize first, then set overflow IRQ and first CC event
nrfx_rtc_uninit(&rtc1);
nrfx_rtc_init(&rtc1, &rtc_config_time_ticks, rtc_irq_time);

Wyświetl plik

@ -54,6 +54,8 @@ void mp_hal_delay_us(mp_uint_t us);
const char *nrfx_error_code_lookup(uint32_t err_code);
void mp_nrf_start_lfclk(void);
#define MP_HAL_PIN_FMT "%q"
#define mp_hal_pin_obj_t const pin_obj_t *
#define mp_hal_get_pin_obj(o) pin_find(o)

Wyświetl plik

@ -10,3 +10,9 @@ require("logging")
# Bluetooth
require("aioble")
# Register external library
add_library("arduino-lib", "$(ARDUINO_LIB_DIR)")
# CMWX1 Lora module.
require("cmwx1", library="arduino-lib")

Wyświetl plik

@ -18,5 +18,8 @@ MICROPY_SSL_MBEDTLS = 1
MICROPY_PY_NETWORK = 1
MICROPY_PY_NETWORK_ESP_HOSTED = 1
ARDUINO_LIB_DIR = lib/arduino-lib
GIT_SUBMODULES += $(ARDUINO_LIB_DIR)
FROZEN_MANIFEST = $(BOARD_DIR)/manifest.py
MICROPY_MANIFEST_ARDUINO_LIB_DIR = $(TOP)/$(ARDUINO_LIB_DIR)
MBEDTLS_CONFIG_FILE = '"$(BOARD_DIR)/mbedtls_config_board.h"'

Wyświetl plik

@ -455,6 +455,15 @@ target_link_options(${MICROPY_TARGET} PRIVATE
-Wl,--wrap=dcd_event_handler
)
# Apply optimisations to performance-critical source code.
set_source_files_properties(
${MICROPY_PY_DIR}/map.c
${MICROPY_PY_DIR}/mpz.c
${MICROPY_PY_DIR}/vm.c
PROPERTIES
COMPILE_OPTIONS "-O2"
)
set_source_files_properties(
${PICO_SDK_PATH}/src/rp2_common/pico_double/double_math.c
${PICO_SDK_PATH}/src/rp2_common/pico_float/float_math.c

Wyświetl plik

@ -37,7 +37,7 @@ You can also build the standard CMake way. The final firmware is found in
the top-level of the CMake build directory (`build` by default) and is
called `firmware.uf2`.
If you are using a different board other than a Rasoberry Pi Pico, then you should
If you are using a board other than a Raspberry Pi Pico, you should
pass the board name to the build; e.g. for Raspberry Pi Pico W:
$ make BOARD=RPI_PICO_W submodules

Wyświetl plik

@ -127,10 +127,10 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) {
const uint32_t xosc_hz = XOSC_MHZ * 1000000;
uint32_t my_interrupts = save_and_disable_interrupts();
uint32_t my_interrupts = mp_thread_begin_atomic_section();
#if MICROPY_PY_NETWORK_CYW43
if (cyw43_has_pending && cyw43_poll != NULL) {
restore_interrupts(my_interrupts);
mp_thread_end_atomic_section(my_interrupts);
return;
}
#endif
@ -165,8 +165,15 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) {
} else {
uint32_t sleep_en0 = clocks_hw->sleep_en0;
uint32_t sleep_en1 = clocks_hw->sleep_en1;
bool timer3_enabled = irq_is_enabled(3);
clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS;
if (use_timer_alarm) {
// Make sure ALARM3/IRQ3 is enabled on _this_ core
timer_hw->inte |= 1 << 3;
if (!timer3_enabled) {
irq_set_enabled(3, true);
}
// Use timer alarm to wake.
clocks_hw->sleep_en1 = CLOCKS_SLEEP_EN1_CLK_SYS_TIMER_BITS;
timer_hw->alarm[3] = timer_hw->timerawl + delay_ms * 1000;
@ -177,6 +184,9 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) {
scb_hw->scr |= M0PLUS_SCR_SLEEPDEEP_BITS;
__wfi();
scb_hw->scr &= ~M0PLUS_SCR_SLEEPDEEP_BITS;
if (!timer3_enabled) {
irq_set_enabled(3, false);
}
clocks_hw->sleep_en0 = sleep_en0;
clocks_hw->sleep_en1 = sleep_en1;
}
@ -186,7 +196,7 @@ static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) {
// Bring back all clocks.
clocks_init();
restore_interrupts(my_interrupts);
mp_thread_end_atomic_section(my_interrupts);
}
NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args) {

Wyświetl plik

@ -23,7 +23,7 @@ bytecode. The cross-compiler is built and run on the host machine, using:
$ make -C mpy-cross
This command should be executed from the root directory of this repository.
All other commands below should be executed from the ports/stm32/ directory.
All other commands below should be executed from the ports/samd/ directory.
An ARM compiler is required for the build, along with the associated binary
utilities. The default compiler is `arm-none-eabi-gcc`, which is available for

Wyświetl plik

@ -1,2 +1,4 @@
#define MICROPY_HW_BOARD_NAME "Trinket M0"
#define MICROPY_HW_MCU_NAME "SAMD21E18A"
#define MICROPY_HW_DFLL_USB_SYNC (1)

Wyświetl plik

@ -1,4 +1,6 @@
#define MICROPY_HW_BOARD_NAME "Mini SAM M4"
#define MICROPY_HW_MCU_NAME "SAMD51G19A"
#define MICROPY_HW_DFLL_USB_SYNC (1)
#define MICROPY_HW_QSPIFLASH GD25Q16C

Wyświetl plik

@ -30,5 +30,5 @@ void init_clocks(uint32_t cpu_freq);
void set_cpu_freq(uint32_t cpu_freq);
uint32_t get_cpu_freq(void);
uint32_t get_peripheral_freq(void);
void check_usb_recovery_mode(void);
void check_usb_clock_recovery_mode(void);
void enable_sercom_clock(int id);

Wyświetl plik

@ -34,6 +34,7 @@
#include "shared/runtime/pyexec.h"
#include "shared/runtime/softtimer.h"
#include "shared/tinyusb/mp_usbd.h"
#include "clock_config.h"
extern uint8_t _sstack, _estack, _sheap, _eheap;
extern void adc_deinit_all(void);
@ -59,6 +60,7 @@ void samd_main(void) {
int ret = pyexec_file_if_exists("boot.py");
mp_usbd_init();
check_usb_clock_recovery_mode();
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;

Wyświetl plik

@ -111,8 +111,31 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
SysTick_Config(cpu_freq / 1000);
}
void check_usb_recovery_mode(void) {
#if !MICROPY_HW_XOSC32K
#if !MICROPY_HW_XOSC32K || MICROPY_HW_DFLL_USB_SYNC
static void sync_dfll48_with_xosc32kulp(void) {
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
}
// Connect GCLK4 to the DFLL input.
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK4 | GCLK_CLKCTRL_ID_DFLL48 | GCLK_CLKCTRL_CLKEN;
while (GCLK->STATUS.bit.SYNCBUSY) {
}
// Set the multiplication values. The offset of 16384 to the freq is for rounding.
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_MUL((CPU_FREQ + 16384) / 32768) |
SYSCTRL_DFLLMUL_FSTEP(1) | SYSCTRL_DFLLMUL_CSTEP(1);
while (SYSCTRL->PCLKSR.bit.DFLLRDY == 0) {
}
// Start the DFLL and wait for the PLL lock. We just wait for the fine lock, since
// coarse adjusting is bypassed.
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_WAITLOCK | SYSCTRL_DFLLCTRL_STABLE |
SYSCTRL_DFLLCTRL_BPLCKC | SYSCTRL_DFLLCTRL_ENABLE;
while (!SYSCTRL->PCLKSR.bit.DFLLLCKF) {
}
}
#endif
void check_usb_clock_recovery_mode(void) {
#if MICROPY_HW_DFLL_USB_SYNC
// Check USB status for up to 1 second. If not connected,
// switch DFLL48M back to open loop
for (int i = 0; i < 100; i++) {
@ -121,10 +144,9 @@ void check_usb_recovery_mode(void) {
}
mp_hal_delay_ms(10);
}
// Set/keep the open loop mode of the device.
SYSCTRL->DFLLVAL.reg = dfll48m_calibration;
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE;
#endif // MICROPY_HW_XOSC32K
// No USB sync. Use XOSC32KULP as clock reference for DFLL48M
sync_dfll48_with_xosc32kulp();
#endif
}
// Purpose of the #defines for the clock configuration.
@ -178,12 +200,12 @@ void init_clocks(uint32_t cpu_freq) {
// GCLK1: 32kHz, source: XOSC32K or OSCULP32K, usage: FDPLL96M reference
// GCLK2: 1-48MHz, source: DFLL48M, usage: Peripherals
// GCLK3: 2Mhz, source: DFLL48M, usage: us-counter (TC4/TC5)
// GCLK4: 32kHz, source: XOSC32K, if crystal present, usage: DFLL48M reference
// GCLK4: 32kHz, source: XOSC32K or OSCULP32K, usage: DFLL48M reference
// GCLK5: 48MHz, source: DFLL48M, usage: USB
// GCLK8: 1kHz, source: XOSC32K or OSCULP32K, usage: WDT and RTC
// DFLL48M: Reference sources:
// - in closed loop mode: either XOSC32K or OSCULP32K or USB clock
// from GCLK4.
// - in closed loop mode: either XOSC32K or OSCULP32K from GCLK4
// or USB clock.
// - in open loop mode: None
// FDPLL96M: Reference source GCLK1
// Used for the CPU clock for freq >= 48Mhz
@ -256,6 +278,17 @@ void init_clocks(uint32_t cpu_freq) {
#else // MICROPY_HW_XOSC32K
// Connect the GCLK1 to the XOSC32KULP
GCLK->GENDIV.reg = GCLK_GENDIV_ID(1) | GCLK_GENDIV_DIV(1);
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(1);
while (GCLK->STATUS.bit.SYNCBUSY) {
}
// Connect the GCLK4 to the XOSC32KULP
GCLK->GENDIV.reg = GCLK_GENDIV_ID(4) | GCLK_GENDIV_DIV(1);
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(4);
while (GCLK->STATUS.bit.SYNCBUSY) {
}
// Enable DFLL48M
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
@ -263,35 +296,30 @@ void init_clocks(uint32_t cpu_freq) {
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk)
>> FUSES_DFLL48M_COARSE_CAL_Pos;
uint32_t fine = (*((uint32_t *)FUSES_DFLL48M_FINE_CAL_ADDR) & FUSES_DFLL48M_FINE_CAL_Msk)
>> FUSES_DFLL48M_COARSE_CAL_Pos;
if (coarse == 0x3f) {
coarse = 0x1f;
}
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) | SYSCTRL_DFLLVAL_FINE(511);
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) | SYSCTRL_DFLLVAL_FINE(fine);
dfll48m_calibration = SYSCTRL_DFLLVAL_COARSE(coarse) | SYSCTRL_DFLLVAL_FINE(fine);
#if MICROPY_HW_DFLL_USB_SYNC
// Configure the DFLL48M for USB clock recovery.
// Will have to switch back if no USB
SYSCTRL->DFLLSYNC.bit.READREQ = 1;
dfll48m_calibration = SYSCTRL->DFLLVAL.reg;
// Set the Multiplication factor.
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) | SYSCTRL_DFLLMUL_FSTEP(1)
| SYSCTRL_DFLLMUL_MUL(48000);
// Set the mode to closed loop USB Recovery mode
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_USBCRM | SYSCTRL_DFLLCTRL_CCDIS
| SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_ENABLE;
#else
// Set/keep the open loop mode of the device.
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE;
#endif
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
}
// Connect the GCLK1 to the XOSC32KULP
GCLK->GENDIV.reg = GCLK_GENDIV_ID(1) | GCLK_GENDIV_DIV(1);
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(1);
while (GCLK->STATUS.bit.SYNCBUSY) {
}
#else // MICROPY_HW_DFLL_USB_SYNC
sync_dfll48_with_xosc32kulp();
#endif // MICROPY_HW_DFLL_USB_SYNC
// Set GCLK8 to 1 kHz.
GCLK->GENDIV.reg = GCLK_GENDIV_ID(8) | GCLK_GENDIV_DIV(32);
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(8);

Wyświetl plik

@ -115,8 +115,8 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
SysTick_Config(cpu_freq / 1000);
}
void check_usb_recovery_mode(void) {
#if !MICROPY_HW_XOSC32K
void check_usb_clock_recovery_mode(void) {
#if MICROPY_HW_DFLL_USB_SYNC
// Check USB status for up to 1 second. If not connected,
// switch DFLL48M back to open loop
for (int i = 0; i < 100; i++) {
@ -144,7 +144,7 @@ void check_usb_recovery_mode(void) {
OSCCTRL->DFLLCTRLB.reg = 0;
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
}
#endif // MICROPY_HW_XOSC32K
#endif
}
// Purpose of the #defines for the clock configuration.

Wyświetl plik

@ -337,9 +337,13 @@ static mp_obj_t samd_qspiflash_make_new(const mp_obj_type_t *type, size_t n_args
// The write in progress bit should be low.
while (read_status() & 0x01) {
}
// The suspended write/erase bit should be low.
while (read_status2() & 0x80) {
if (!flash_device->single_status_byte) {
// The suspended write/erase bit should be low.
while (read_status2() & 0x80) {
}
}
run_command(QSPI_CMD_ENABLE_RESET);
run_command(QSPI_CMD_RESET);
// Wait 30us for the reset

Wyświetl plik

@ -116,7 +116,6 @@ void samd_init(void) {
init_clocks(get_cpu_freq());
init_us_counter();
usb_init();
check_usb_recovery_mode();
#if defined(MCU_SAMD51)
mp_hal_ticks_cpu_enable();
#endif

Wyświetl plik

@ -49,6 +49,9 @@ const uint8_t _COMMANDS_32BIT[] = {0x13, 0x12, 0x21}; // READ, PROGRAM_PAGE, ER
#define COMMAND_READ_SFDP (0x5A)
#define PAGE_SIZE (256)
#define SECTOR_SIZE (4096)
#ifndef MICROPY_HW_SPIFLASH_BAUDRATE
#define MICROPY_HW_SPIFLASH_BAUDRATE (24000000)
#endif
typedef struct _spiflash_obj_t {
mp_obj_base_t base;
@ -136,7 +139,7 @@ static mp_obj_t spiflash_make_new(const mp_obj_type_t *type, size_t n_args, size
mp_obj_t spi_args[] = {
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_SPIFLASH_ID),
MP_OBJ_NEW_SMALL_INT(24000000), // baudrate
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_SPIFLASH_BAUDRATE),
MP_OBJ_NEW_QSTR(MP_QSTR_mosi), MP_OBJ_NEW_QSTR(MP_QSTR_FLASH_MOSI),
MP_OBJ_NEW_QSTR(MP_QSTR_miso), MP_OBJ_NEW_QSTR(MP_QSTR_FLASH_MISO),
MP_OBJ_NEW_QSTR(MP_QSTR_sck), MP_OBJ_NEW_QSTR(MP_QSTR_FLASH_SCK),

Wyświetl plik

@ -2,9 +2,9 @@ MicroPython port to STM32 MCUs
==============================
This directory contains the port of MicroPython to ST's line of STM32
microcontrollers. Supported MCU series are: STM32F0, STM32F4, STM32F7,
STM32H7, STM32L0, STM32L4 and STM32WB. Parts of the code here utilise the
STM32Cube HAL library.
microcontrollers. Supported MCU series are: STM32F0, STM32F4, STM32F7, STM32G0,
STM32G4, STM32H5, STM32H7, STM32L0, STM32L1, STM32L4, STM32WL and STM32WB.
Parts of the code here utilise the STM32Cube HAL library.
The officially supported boards are the line of pyboards: PYBv1.0 and PYBv1.1
(both with STM32F405), PYBLITEv1.0 (with STM32F411) and PYBD-SFx (with
@ -16,12 +16,6 @@ Other boards that are supported include ST Discovery and Nucleo boards.
See the boards/ subdirectory, which contains the configuration files used
to build each individual board.
The STM32H7 series has preliminary support: there is a working REPL via
USB and UART, as well as very basic peripheral support, but some things do
not work and none of the advanced features of the STM32H7 are yet supported,
such as the clock tree. At this point the STM32H7 should be considered as a
fast version of the STM32F7.
Build instructions
------------------

Wyświetl plik

@ -10,3 +10,9 @@ require("logging")
# Bluetooth
require("aioble")
# Register external library
add_library("arduino-lib", "$(ARDUINO_LIB_DIR)")
# RPC
require("msgpackrpc", library="arduino-lib")

Wyświetl plik

@ -26,5 +26,8 @@ MICROPY_SSL_MBEDTLS = 1
MICROPY_PY_OPENAMP = 1
MICROPY_PY_OPENAMP_REMOTEPROC = 1
ARDUINO_LIB_DIR = lib/arduino-lib
GIT_SUBMODULES += $(ARDUINO_LIB_DIR)
FROZEN_MANIFEST = $(BOARD_DIR)/manifest.py
MICROPY_MANIFEST_ARDUINO_LIB_DIR = $(TOP)/$(ARDUINO_LIB_DIR)
MBEDTLS_CONFIG_FILE = '"$(BOARD_DIR)/mbedtls_config_board.h"'

Wyświetl plik

@ -10,3 +10,9 @@ require("logging")
# Bluetooth
require("aioble")
# Register external library
add_library("arduino-lib", "$(ARDUINO_LIB_DIR)")
# RPC
require("msgpackrpc", library="arduino-lib")

Wyświetl plik

@ -26,5 +26,8 @@ MICROPY_SSL_MBEDTLS = 1
MICROPY_PY_OPENAMP = 1
MICROPY_PY_OPENAMP_REMOTEPROC = 1
ARDUINO_LIB_DIR = lib/arduino-lib
GIT_SUBMODULES += $(ARDUINO_LIB_DIR)
FROZEN_MANIFEST = $(BOARD_DIR)/manifest.py
MICROPY_MANIFEST_ARDUINO_LIB_DIR = $(TOP)/$(ARDUINO_LIB_DIR)
MBEDTLS_CONFIG_FILE = '"$(BOARD_DIR)/mbedtls_config_board.h"'

Wyświetl plik

@ -10,3 +10,10 @@ require("logging")
# Bluetooth
require("aioble")
# Register external library
add_library("arduino-lib", "$(ARDUINO_LIB_DIR)")
# RPC
require("cmwx1", library="arduino-lib")
require("msgpackrpc", library="arduino-lib")

Wyświetl plik

@ -26,5 +26,8 @@ MICROPY_SSL_MBEDTLS = 1
MICROPY_PY_OPENAMP = 1
MICROPY_PY_OPENAMP_REMOTEPROC = 1
ARDUINO_LIB_DIR = lib/arduino-lib
GIT_SUBMODULES += $(ARDUINO_LIB_DIR)
FROZEN_MANIFEST = $(BOARD_DIR)/manifest.py
MICROPY_MANIFEST_ARDUINO_LIB_DIR = $(TOP)/$(ARDUINO_LIB_DIR)
MBEDTLS_CONFIG_FILE = '"$(BOARD_DIR)/mbedtls_config_board.h"'

Wyświetl plik

@ -198,9 +198,9 @@ void board_mboot_state_change(int state, uint32_t arg) {
// The FS-load update is about to start. Program the update key and FS-load elements
// into the flash so they can be retrieved if there is a power failure during the update.
mp_spiflash_erase_block(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR);
mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR + 4, ELEM_DATA_SIZE, ELEM_DATA_START);
uint32_t key = SPIFLASH_UPDATE_KEY_VALUE;
mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR, 4, (const uint8_t *)&key);
mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR + 4, ELEM_DATA_SIZE, ELEM_DATA_START);
} else if (state == MBOOT_STATE_FSLOAD_END) {
// The FS-load update completed (either with success or failure), so erase the
// update key and write the result of the FS-load operation into flash.

Wyświetl plik

@ -199,7 +199,14 @@ int board_mboot_get_reset_mode(uint32_t *initial_r0) {
}
void board_mboot_state_change(int state, uint32_t arg) {
if (state == MBOOT_STATE_FSLOAD_END) {
if (state == MBOOT_STATE_FSLOAD_START) {
// The FS-load update is about to start. Program the update key and FS-load elements
// into the flash so they can be retrieved if there is a power failure during the update.
mp_spiflash_erase_block(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR);
mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR + 4, ELEM_DATA_SIZE, ELEM_DATA_START);
uint32_t key = SPIFLASH_UPDATE_KEY_VALUE;
mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR, 4, (const uint8_t *)&key);
} else if (state == MBOOT_STATE_FSLOAD_END) {
// The FS-load update completed (either with success or failure), so erase the
// update key and write the result of the FS-load operation into flash.
mp_spiflash_erase_block(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR);

Wyświetl plik

@ -24,6 +24,7 @@
* THE SOFTWARE.
*/
#include <string.h>
#include "py/mpconfig.h"
#include "py/misc.h"
#include "py/mphal.h"
@ -450,28 +451,38 @@ int flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) {
#endif
}
#elif defined(STM32H5)
#elif defined(STM32H5) || defined(STM32H7)
// program the flash 128 bits (4 words) at a time
for (int i = 0; i < num_word32 / 4; i++) {
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, flash_dest, (uint64_t)(uint32_t)src);
if (status != HAL_OK) {
break;
#if defined(STM32H5)
static const unsigned int WORD32_PER_FLASHWORD = 4;
static const unsigned int PROGRAM_TYPE = FLASH_TYPEPROGRAM_QUADWORD;
#else
static const unsigned int WORD32_PER_FLASHWORD = FLASH_NB_32BITWORD_IN_FLASHWORD;
static const unsigned int PROGRAM_TYPE = FLASH_TYPEPROGRAM_FLASHWORD;
#endif
if (flash_dest % (WORD32_PER_FLASHWORD * sizeof(uint32_t))) {
// The flash_dest address is not aligned correctly.
status = HAL_ERROR;
} else {
// Program the flash WORD32_PER_FLASHWORD words at a time.
for (int i = 0; i < num_word32 / WORD32_PER_FLASHWORD; i++) {
status = HAL_FLASH_Program(PROGRAM_TYPE, flash_dest, (uint32_t)src);
if (status != HAL_OK) {
break;
}
flash_dest += WORD32_PER_FLASHWORD * sizeof(uint32_t);
src += WORD32_PER_FLASHWORD;
}
flash_dest += 16;
src += 4;
}
#elif defined(STM32H7)
// program the flash 256 bits at a time
for (int i = 0; i < num_word32 / 8; i++) {
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, flash_dest, (uint64_t)(uint32_t)src);
if (status != HAL_OK) {
break;
// Program any remaining words from src.
// Additional bytes beyond that are programmed to 0xff.
if (num_word32 % WORD32_PER_FLASHWORD) {
uint32_t buf[WORD32_PER_FLASHWORD];
memset(buf, 0xff, sizeof(buf));
memcpy(buf, src, (num_word32 % WORD32_PER_FLASHWORD) * sizeof(uint32_t));
status = HAL_FLASH_Program(PROGRAM_TYPE, flash_dest, (uint32_t)buf);
}
flash_dest += 32;
src += 8;
}
#else

Wyświetl plik

@ -477,6 +477,7 @@ void stm32_main(uint32_t reset_mode) {
memcpy(&buf[0], "PYBD", 4);
mp_hal_get_mac_ascii(MP_HAL_MAC_WLAN0, 8, 4, (char *)&buf[4]);
cyw43_wifi_ap_set_ssid(&cyw43_state, 8, buf);
cyw43_wifi_ap_set_auth(&cyw43_state, CYW43_AUTH_WPA2_MIXED_PSK);
cyw43_wifi_ap_set_password(&cyw43_state, 8, (const uint8_t *)"pybd0123");
}
#endif

Wyświetl plik

@ -42,6 +42,17 @@
#define MBOOT_PACK_GZIP_BUFFER_SIZE (2048)
#endif
// Configure the minimum number of bytes that can be written at once to the internal flash.
#if defined(STM32H5)
#define FLASH_MIN_WRITE_BYTES (16)
#elif defined(STM32H7)
#define FLASH_MIN_WRITE_BYTES (4 * FLASH_NB_32BITWORD_IN_FLASHWORD)
#else
// This default is 8 bytes due to STM32WB MCUs requiring that a double-word write
// to flash can only be done once (due to ECC).
#define FLASH_MIN_WRITE_BYTES (8)
#endif
// State to manage automatic flash erasure.
static uint32_t erased_base_addr;
static uint32_t erased_top_addr;
@ -57,9 +68,8 @@ static uint8_t decrypted_buf[MBOOT_PACK_DFU_CHUNK_BUF_SIZE] __attribute__((align
static uint8_t uncompressed_buf[MBOOT_PACK_GZIP_BUFFER_SIZE] __attribute__((aligned(8)));
// Buffer to hold the start of the firmware, which is only written once the
// entire firmware is validated. This is 8 bytes due to STM32WB MCUs requiring
// that a double-word write to flash can only be done once (due to ECC).
static uint8_t firmware_head[8] __attribute__((aligned(8)));
// entire firmware is validated.
static uint8_t firmware_head[FLASH_MIN_WRITE_BYTES] __attribute__((aligned(FLASH_MIN_WRITE_BYTES)));
// Flag to indicate that firmware_head contains valid data.
static bool firmware_head_valid;
@ -100,7 +110,7 @@ static int mboot_pack_commit_chunk(uint32_t addr, uint8_t *data, size_t len) {
return ret;
}
if (addr == APPLICATION_ADDR) {
if (addr == APPLICATION_ADDR && len >= sizeof(firmware_head)) {
// Don't write the very start of the firmware, just copy it into a temporary buffer.
// It will be written only if the full firmware passes the checksum/signature.
memcpy(firmware_head, data, sizeof(firmware_head));

Wyświetl plik

@ -40,11 +40,9 @@
#include "metal/utilities.h"
#include "extmod/modopenamp_remoteproc.h"
#define DEBUG_printf(...) // mp_printf(&mp_plat_print, __VA_ARGS__)
struct remoteproc *mp_openamp_remoteproc_init(struct remoteproc *rproc,
const struct remoteproc_ops *ops, void *arg) {
DEBUG_printf("rproc_init()\n");
metal_log(METAL_LOG_DEBUG, "rproc_init()\n");
rproc->ops = ops;
rproc->state = RPROC_OFFLINE;
@ -56,7 +54,7 @@ struct remoteproc *mp_openamp_remoteproc_init(struct remoteproc *rproc,
void *mp_openamp_remoteproc_mmap(struct remoteproc *rproc, metal_phys_addr_t *pa,
metal_phys_addr_t *da, size_t size, unsigned int attribute,
struct metal_io_region **io) {
DEBUG_printf("rproc_mmap(): pa 0x%p da 0x%p io 0x%p size %u\n", *pa, *da, *io, size);
metal_log(METAL_LOG_DEBUG, "rproc_mmap(): pa 0x%p da 0x%p io 0x%p size %u\n", *pa, *da, *io, size);
struct remoteproc_mem *mem;
metal_phys_addr_t lpa = *pa;
@ -100,11 +98,11 @@ void *mp_openamp_remoteproc_mmap(struct remoteproc *rproc, metal_phys_addr_t *pa
}
int mp_openamp_remoteproc_start(struct remoteproc *rproc) {
DEBUG_printf("rproc_start()\n");
metal_log(METAL_LOG_DEBUG, "rproc_start()\n");
if ((RCC->GCR & RCC_GCR_BOOT_C2) || (FLASH->OPTSR_CUR & FLASH_OPTSR_BCM4)) {
// The CM4 core has already been started manually, or auto-boot is enabled
// via the option bytes, in either case the core can't be restarted.
DEBUG_printf("rproc_start(): CM4 core is already booted.\n");
metal_log(METAL_LOG_DEBUG, "rproc_start(): CM4 core is already booted.\n");
return -1;
}
@ -122,7 +120,7 @@ int mp_openamp_remoteproc_start(struct remoteproc *rproc) {
}
int mp_openamp_remoteproc_stop(struct remoteproc *rproc) {
DEBUG_printf("rproc_stop()\n");
metal_log(METAL_LOG_DEBUG, "rproc_stop()\n");
if (rproc->state == RPROC_RUNNING) {
// There's no straightforward way to reset or shut down
// the remote processor, so a full system reset is needed.
@ -132,18 +130,18 @@ int mp_openamp_remoteproc_stop(struct remoteproc *rproc) {
}
int mp_openamp_remoteproc_config(struct remoteproc *rproc, void *data) {
DEBUG_printf("rproc_config()\n");
metal_log(METAL_LOG_DEBUG, "rproc_config()\n");
(void)rproc;
return 0;
}
void mp_openamp_remoteproc_remove(struct remoteproc *rproc) {
DEBUG_printf("rproc_remove()\n");
metal_log(METAL_LOG_DEBUG, "rproc_remove()\n");
(void)rproc;
}
int mp_openamp_remoteproc_shutdown(struct remoteproc *rproc) {
DEBUG_printf("rproc_shutdown()\n");
metal_log(METAL_LOG_DEBUG, "rproc_shutdown()\n");
if (rproc->state == RPROC_RUNNING) {
// There's no straightforward way to reset or shut down
// the remote processor, so a full system reset is needed.

Wyświetl plik

@ -22,6 +22,9 @@ BUILD ?= build-$(VARIANT)
include ../../py/mkenv.mk
include $(VARIANT_DIR)/mpconfigvariant.mk
# Use the default frozen manifest, variants may override this.
FROZEN_MANIFEST ?= variants/manifest.py
# Qstr definitions (must come before including py.mk).
QSTR_DEFS = qstrdefsport.h

Wyświetl plik

@ -38,7 +38,7 @@ export async function loadMicroPython(options) {
{ heapsize: 1024 * 1024, linebuffer: true },
options,
);
const Module = {};
let Module = {};
Module.locateFile = (path, scriptDirectory) =>
url || scriptDirectory + path;
Module._textDecoder = new TextDecoder();
@ -83,11 +83,7 @@ export async function loadMicroPython(options) {
Module.stderr = (c) => stderr(new Uint8Array([c]));
}
}
const moduleLoaded = new Promise((r) => {
Module.postRun = r;
});
_createMicroPythonModule(Module);
await moduleLoaded;
Module = await _createMicroPythonModule(Module);
globalThis.Module = Module;
proxy_js_init();
const pyimport = (name) => {
@ -131,23 +127,31 @@ export async function loadMicroPython(options) {
},
pyimport: pyimport,
runPython(code) {
const len = Module.lengthBytesUTF8(code);
const buf = Module._malloc(len + 1);
Module.stringToUTF8(code, buf, len + 1);
const value = Module._malloc(3 * 4);
Module.ccall(
"mp_js_do_exec",
"number",
["string", "pointer"],
[code, value],
["pointer", "number", "pointer"],
[buf, len, value],
);
Module._free(buf);
return proxy_convert_mp_to_js_obj_jsside_with_free(value);
},
runPythonAsync(code) {
const len = Module.lengthBytesUTF8(code);
const buf = Module._malloc(len + 1);
Module.stringToUTF8(code, buf, len + 1);
const value = Module._malloc(3 * 4);
Module.ccall(
"mp_js_do_exec_async",
"number",
["string", "pointer"],
[code, value],
["pointer", "number", "pointer"],
[buf, len, value],
);
Module._free(buf);
return proxy_convert_mp_to_js_obj_jsside_with_free(value);
},
replInit() {
@ -224,6 +228,16 @@ async function runCLI() {
}
});
} else {
// If the script to run ends with a running of the asyncio main loop, then inject
// a simple `asyncio.run` hook that starts the main task. This is primarily to
// support running the standard asyncio tests.
if (contents.endsWith("asyncio.run(main())\n")) {
const asyncio = mp.pyimport("asyncio");
asyncio.run = async (task) => {
await asyncio.create_task(task);
};
}
try {
mp.runPython(contents);
} catch (error) {

Wyświetl plik

@ -0,0 +1,9 @@
# MicroPython asyncio module, for use with webassembly port
# MIT license; Copyright (c) 2024 Damien P. George
from .core import *
from .funcs import wait_for, wait_for_ms, gather
from .event import Event
from .lock import Lock
__version__ = (3, 0, 0)

Wyświetl plik

@ -0,0 +1,249 @@
# MicroPython asyncio module, for use with webassembly port
# MIT license; Copyright (c) 2019-2024 Damien P. George
from time import ticks_ms as ticks, ticks_diff, ticks_add
import sys, js, jsffi
# Import TaskQueue and Task from built-in C code.
from _asyncio import TaskQueue, Task
################################################################################
# Exceptions
class CancelledError(BaseException):
pass
class TimeoutError(Exception):
pass
# Used when calling Loop.call_exception_handler.
_exc_context = {"message": "Task exception wasn't retrieved", "exception": None, "future": None}
################################################################################
# Sleep functions
# "Yield" once, then raise StopIteration
class SingletonGenerator:
def __init__(self):
self.state = None
self.exc = StopIteration()
def __iter__(self):
return self
def __next__(self):
if self.state is not None:
_task_queue.push(cur_task, self.state)
self.state = None
return None
else:
self.exc.__traceback__ = None
raise self.exc
# Pause task execution for the given time (integer in milliseconds, uPy extension)
# Use a SingletonGenerator to do it without allocating on the heap
def sleep_ms(t, sgen=SingletonGenerator()):
if cur_task is None:
# Support top-level asyncio.sleep, via a JavaScript Promise.
return jsffi.async_timeout_ms(t)
assert sgen.state is None
sgen.state = ticks_add(ticks(), max(0, t))
return sgen
# Pause task execution for the given time (in seconds)
def sleep(t):
return sleep_ms(int(t * 1000))
################################################################################
# Main run loop
asyncio_timer = None
class ThenableEvent:
def __init__(self, thenable):
self.result = None # Result of the thenable
self.waiting = None # Task waiting on completion of this thenable
thenable.then(self.set)
def set(self, value):
# Thenable/Promise is fulfilled, set result and schedule any waiting task.
self.result = value
if self.waiting:
_task_queue.push(self.waiting)
self.waiting = None
_schedule_run_iter(0)
def remove(self, task):
self.waiting = None
# async
def wait(self):
# Set the calling task as the task waiting on this thenable.
self.waiting = cur_task
# Set calling task's data to this object so it can be removed if needed.
cur_task.data = self
# Wait for the thenable to fulfill.
yield
# Return the result of the thenable.
return self.result
# Ensure the awaitable is a task
def _promote_to_task(aw):
return aw if isinstance(aw, Task) else create_task(aw)
def _schedule_run_iter(dt):
global asyncio_timer
if asyncio_timer is not None:
js.clearTimeout(asyncio_timer)
asyncio_timer = js.setTimeout(_run_iter, dt)
def _run_iter():
global cur_task
excs_all = (CancelledError, Exception) # To prevent heap allocation in loop
excs_stop = (CancelledError, StopIteration) # To prevent heap allocation in loop
while True:
# Wait until the head of _task_queue is ready to run
t = _task_queue.peek()
if t:
# A task waiting on _task_queue; "ph_key" is time to schedule task at
dt = max(0, ticks_diff(t.ph_key, ticks()))
else:
# No tasks can be woken so finished running
cur_task = None
return
if dt > 0:
# schedule to call again later
cur_task = None
_schedule_run_iter(dt)
return
# Get next task to run and continue it
t = _task_queue.pop()
cur_task = t
try:
# Continue running the coroutine, it's responsible for rescheduling itself
exc = t.data
if not exc:
t.coro.send(None)
else:
# If the task is finished and on the run queue and gets here, then it
# had an exception and was not await'ed on. Throwing into it now will
# raise StopIteration and the code below will catch this and run the
# call_exception_handler function.
t.data = None
t.coro.throw(exc)
except excs_all as er:
# Check the task is not on any event queue
assert t.data is None
# This task is done.
if t.state:
# Task was running but is now finished.
waiting = False
if t.state is True:
# "None" indicates that the task is complete and not await'ed on (yet).
t.state = None
elif callable(t.state):
# The task has a callback registered to be called on completion.
t.state(t, er)
t.state = False
waiting = True
else:
# Schedule any other tasks waiting on the completion of this task.
while t.state.peek():
_task_queue.push(t.state.pop())
waiting = True
# "False" indicates that the task is complete and has been await'ed on.
t.state = False
if not waiting and not isinstance(er, excs_stop):
# An exception ended this detached task, so queue it for later
# execution to handle the uncaught exception if no other task retrieves
# the exception in the meantime (this is handled by Task.throw).
_task_queue.push(t)
# Save return value of coro to pass up to caller.
t.data = er
elif t.state is None:
# Task is already finished and nothing await'ed on the task,
# so call the exception handler.
# Save exception raised by the coro for later use.
t.data = exc
# Create exception context and call the exception handler.
_exc_context["exception"] = exc
_exc_context["future"] = t
Loop.call_exception_handler(_exc_context)
# Create and schedule a new task from a coroutine.
def create_task(coro):
if not hasattr(coro, "send"):
raise TypeError("coroutine expected")
t = Task(coro, globals())
_task_queue.push(t)
_schedule_run_iter(0)
return t
################################################################################
# Event loop wrapper
cur_task = None
class Loop:
_exc_handler = None
def create_task(coro):
return create_task(coro)
def close():
pass
def set_exception_handler(handler):
Loop._exc_handler = handler
def get_exception_handler():
return Loop._exc_handler
def default_exception_handler(loop, context):
print(context["message"], file=sys.stderr)
print("future:", context["future"], "coro=", context["future"].coro, file=sys.stderr)
sys.print_exception(context["exception"], sys.stderr)
def call_exception_handler(context):
(Loop._exc_handler or Loop.default_exception_handler)(Loop, context)
def get_event_loop():
return Loop
def current_task():
if cur_task is None:
raise RuntimeError("no running event loop")
return cur_task
def new_event_loop():
global _task_queue
_task_queue = TaskQueue() # TaskQueue of Task instances.
return Loop
# Initialise default event loop.
new_event_loop()

Wyświetl plik

@ -104,7 +104,7 @@ void mp_js_do_import(const char *name, uint32_t *out) {
}
}
void mp_js_do_exec(const char *src, uint32_t *out) {
void mp_js_do_exec(const char *src, size_t len, uint32_t *out) {
// Collect at the top-level, where there are no root pointers from stack/registers.
gc_collect_start();
gc_collect_end();
@ -112,7 +112,7 @@ void mp_js_do_exec(const char *src, uint32_t *out) {
mp_parse_input_kind_t input_kind = MP_PARSE_FILE_INPUT;
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_lexer_t *lex = mp_lexer_new_from_str_len_dedent(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
mp_lexer_t *lex = mp_lexer_new_from_str_len_dedent(MP_QSTR__lt_stdin_gt_, src, len, 0);
qstr source_name = lex->source_name;
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false);
@ -125,9 +125,9 @@ void mp_js_do_exec(const char *src, uint32_t *out) {
}
}
void mp_js_do_exec_async(const char *src, uint32_t *out) {
void mp_js_do_exec_async(const char *src, size_t len, uint32_t *out) {
mp_compile_allow_top_level_await = true;
mp_js_do_exec(src, out);
mp_js_do_exec(src, len, out);
mp_compile_allow_top_level_await = false;
}

Wyświetl plik

@ -61,12 +61,27 @@ static mp_obj_t mp_jsffi_to_js(mp_obj_t arg) {
}
static MP_DEFINE_CONST_FUN_OBJ_1(mp_jsffi_to_js_obj, mp_jsffi_to_js);
// *FORMAT-OFF*
EM_JS(void, promise_with_timeout_ms, (double ms, uint32_t * out), {
const ret = new Promise((resolve) => setTimeout(resolve, ms));
proxy_convert_js_to_mp_obj_jsside(ret, out);
});
// *FORMAT-ON*
static mp_obj_t mp_jsffi_async_timeout_ms(mp_obj_t arg) {
uint32_t out[PVN];
promise_with_timeout_ms(mp_obj_get_float_to_d(arg), out);
return proxy_convert_js_to_mp_obj_cside(out);
}
static MP_DEFINE_CONST_FUN_OBJ_1(mp_jsffi_async_timeout_ms_obj, mp_jsffi_async_timeout_ms);
static const mp_rom_map_elem_t mp_module_jsffi_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_jsffi) },
{ MP_ROM_QSTR(MP_QSTR_JsProxy), MP_ROM_PTR(&mp_type_jsproxy) },
{ MP_ROM_QSTR(MP_QSTR_create_proxy), MP_ROM_PTR(&mp_jsffi_create_proxy_obj) },
{ MP_ROM_QSTR(MP_QSTR_to_js), MP_ROM_PTR(&mp_jsffi_to_js_obj) },
{ MP_ROM_QSTR(MP_QSTR_async_timeout_ms), MP_ROM_PTR(&mp_jsffi_async_timeout_ms_obj) },
};
static MP_DEFINE_CONST_DICT(mp_module_jsffi_globals, mp_module_jsffi_globals_table);

Wyświetl plik

@ -48,9 +48,17 @@ EM_JS(bool, lookup_attr, (int jsref, const char *str, uint32_t * out), {
const attr = UTF8ToString(str);
if (attr in base) {
let value = base[attr];
if (typeof value == "function") {
if (typeof value === "function") {
if (base !== globalThis) {
value = value.bind(base);
if ("_ref" in value) {
// This is a proxy of a Python function, it doesn't need
// binding. And not binding it means if it's passed back
// to Python then it can be extracted from the proxy as a
// true Python function.
} else {
// A function that is not a Python function. Bind it.
value = value.bind(base);
}
}
}
proxy_convert_js_to_mp_obj_jsside(value, out);
@ -338,6 +346,12 @@ typedef struct _jsproxy_gen_t {
mp_vm_return_kind_t jsproxy_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
jsproxy_gen_t *self = MP_OBJ_TO_PTR(self_in);
if (throw_value) {
*ret_val = throw_value;
return MP_VM_RETURN_EXCEPTION;
}
switch (self->state) {
case JSOBJ_GEN_STATE_WAITING:
self->state = JSOBJ_GEN_STATE_COMPLETED;
@ -460,9 +474,29 @@ static mp_obj_t jsproxy_new_gen(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
/******************************************************************************/
#if MICROPY_PY_ASYNCIO
extern mp_obj_t mp_asyncio_context;
#endif
static mp_obj_t jsproxy_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in);
if (has_attr(self->ref, "then")) {
#if MICROPY_PY_ASYNCIO
// When asyncio is running and the caller here is a task, wrap the JavaScript
// thenable in a ThenableEvent, and get the task to wait on that event. This
// decouples the task from the thenable and allows cancelling the task.
if (mp_asyncio_context != MP_OBJ_NULL) {
mp_obj_t cur_task = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
if (cur_task != mp_const_none) {
mp_obj_t thenable_event_class = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_ThenableEvent));
mp_obj_t thenable_event = mp_call_function_1(thenable_event_class, self_in);
mp_obj_t dest[2];
mp_load_method(thenable_event, MP_QSTR_wait, dest);
mp_obj_t wait_gen = mp_call_method_n_kw(0, 0, dest);
return mp_getiter(wait_gen, iter_buf);
}
}
#endif
return jsproxy_new_gen(self_in, iter_buf);
} else {
return jsproxy_new_it(self_in, iter_buf);

Wyświetl plik

@ -289,16 +289,18 @@ void proxy_c_to_js_get_dict(uint32_t c_ref, uint32_t *out) {
static const mp_obj_fun_builtin_var_t resume_obj;
EM_JS(void, js_then_resolve, (uint32_t * resolve, uint32_t * reject), {
EM_JS(void, js_then_resolve, (uint32_t * ret_value, uint32_t * resolve, uint32_t * reject), {
const ret_value_js = proxy_convert_mp_to_js_obj_jsside(ret_value);
const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve);
const reject_js = proxy_convert_mp_to_js_obj_jsside(reject);
resolve_js(null);
resolve_js(ret_value_js);
});
EM_JS(void, js_then_reject, (uint32_t * resolve, uint32_t * reject), {
EM_JS(void, js_then_reject, (uint32_t * ret_value, uint32_t * resolve, uint32_t * reject), {
const ret_value_js = proxy_convert_mp_to_js_obj_jsside(ret_value);
const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve);
const reject_js = proxy_convert_mp_to_js_obj_jsside(reject);
reject_js(null);
reject_js(ret_value_js);
});
// *FORMAT-OFF*
@ -306,14 +308,34 @@ EM_JS(void, js_then_continue, (int jsref, uint32_t * py_resume, uint32_t * resol
const py_resume_js = proxy_convert_mp_to_js_obj_jsside(py_resume);
const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve);
const reject_js = proxy_convert_mp_to_js_obj_jsside(reject);
const ret = proxy_js_ref[jsref].then((x) => {py_resume_js(x, resolve_js, reject_js);}, reject_js);
const ret = proxy_js_ref[jsref].then(
(result) => {
// The Promise is fulfilled on the JavaScript side. Take the result and
// send it to the encapsulating generator on the Python side, so it
// becomes the result of the "yield from" that deferred to this Promise.
py_resume_js(result, null, resolve_js, reject_js);
},
(reason) => {
// The Promise is rejected on the JavaScript side. Take the reason and
// throw it into the encapsulating generator on the Python side.
py_resume_js(null, reason, resolve_js, reject_js);
},
);
proxy_convert_js_to_mp_obj_jsside(ret, out);
});
// *FORMAT-ON*
static mp_obj_t proxy_resume_execute(mp_obj_t self_in, mp_obj_t value, mp_obj_t resolve, mp_obj_t reject) {
static mp_obj_t proxy_resume_execute(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t resolve, mp_obj_t reject) {
if (throw_value != MP_OBJ_NULL && throw_value != mp_const_none) {
if (send_value == mp_const_none) {
send_value = MP_OBJ_NULL;
}
} else {
throw_value = MP_OBJ_NULL;
}
mp_obj_t ret_value;
mp_vm_return_kind_t ret_kind = mp_resume(self_in, value, MP_OBJ_NULL, &ret_value);
mp_vm_return_kind_t ret_kind = mp_resume(self_in, send_value, throw_value, &ret_value);
uint32_t out_resolve[PVN];
uint32_t out_reject[PVN];
@ -321,7 +343,9 @@ static mp_obj_t proxy_resume_execute(mp_obj_t self_in, mp_obj_t value, mp_obj_t
proxy_convert_mp_to_js_obj_cside(reject, out_reject);
if (ret_kind == MP_VM_RETURN_NORMAL) {
js_then_resolve(out_resolve, out_reject);
uint32_t out_ret_value[PVN];
proxy_convert_mp_to_js_obj_cside(ret_value, out_ret_value);
js_then_resolve(out_ret_value, out_resolve, out_reject);
return mp_const_none;
} else if (ret_kind == MP_VM_RETURN_YIELD) {
// ret_value should be a JS thenable
@ -332,17 +356,19 @@ static mp_obj_t proxy_resume_execute(mp_obj_t self_in, mp_obj_t value, mp_obj_t
uint32_t out[PVN];
js_then_continue(ref, out_py_resume, out_resolve, out_reject, out);
return proxy_convert_js_to_mp_obj_cside(out);
} else {
// MP_VM_RETURN_EXCEPTION;
js_then_reject(out_resolve, out_reject);
nlr_raise(ret_value);
} else { // ret_kind == MP_VM_RETURN_EXCEPTION;
// Pass the exception through as an object to reject the promise (don't raise/throw it).
uint32_t out_ret_value[PVN];
proxy_convert_mp_to_js_obj_cside(ret_value, out_ret_value);
js_then_reject(out_ret_value, out_resolve, out_reject);
return mp_const_none;
}
}
static mp_obj_t resume_fun(size_t n_args, const mp_obj_t *args) {
return proxy_resume_execute(args[0], args[1], args[2], args[3]);
return proxy_resume_execute(args[0], args[1], args[2], args[3], args[4]);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(resume_obj, 4, 4, resume_fun);
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(resume_obj, 5, 5, resume_fun);
void proxy_c_to_js_resume(uint32_t c_ref, uint32_t *args) {
nlr_buf_t nlr;
@ -350,7 +376,7 @@ void proxy_c_to_js_resume(uint32_t c_ref, uint32_t *args) {
mp_obj_t obj = proxy_c_get_obj(c_ref);
mp_obj_t resolve = proxy_convert_js_to_mp_obj_cside(args + 1 * 3);
mp_obj_t reject = proxy_convert_js_to_mp_obj_cside(args + 2 * 3);
mp_obj_t ret = proxy_resume_execute(obj, mp_const_none, resolve, reject);
mp_obj_t ret = proxy_resume_execute(obj, mp_const_none, mp_const_none, resolve, reject);
nlr_pop();
return proxy_convert_mp_to_js_obj_cside(ret, args);
} else {

Wyświetl plik

@ -89,7 +89,22 @@ function proxy_call_python(target, argumentsList) {
if (argumentsList.length > 0) {
Module._free(args);
}
return proxy_convert_mp_to_js_obj_jsside_with_free(value);
const ret = proxy_convert_mp_to_js_obj_jsside_with_free(value);
if (ret instanceof PyProxyThenable) {
// In Python when an async function is called it creates the
// corresponding "generator", which must then be executed at
// the top level by an asyncio-like scheduler. In JavaScript
// the semantics for async functions is that they are started
// immediately (their non-async prefix code is executed immediately)
// and only if they await do they return a Promise to delay the
// execution of the remainder of the function.
//
// Emulate the JavaScript behaviour here by resolving the Python
// async function. We assume that the caller who gets this
// return is JavaScript.
return Promise.resolve(ret);
}
return ret;
}
function proxy_convert_js_to_mp_obj_jsside(js_obj, out) {
@ -120,10 +135,11 @@ function proxy_convert_js_to_mp_obj_jsside(js_obj, out) {
Module.stringToUTF8(js_obj, buf, len + 1);
Module.setValue(out + 4, len, "i32");
Module.setValue(out + 8, buf, "i32");
} else if (js_obj instanceof PyProxy) {
kind = PROXY_KIND_JS_PYPROXY;
Module.setValue(out + 4, js_obj._ref, "i32");
} else if (js_obj instanceof PyProxyThenable) {
} else if (
js_obj instanceof PyProxy ||
(typeof js_obj === "function" && "_ref" in js_obj) ||
js_obj instanceof PyProxyThenable
) {
kind = PROXY_KIND_JS_PYPROXY;
Module.setValue(out + 4, js_obj._ref, "i32");
} else {
@ -136,7 +152,11 @@ function proxy_convert_js_to_mp_obj_jsside(js_obj, out) {
}
function proxy_convert_js_to_mp_obj_jsside_force_double_proxy(js_obj, out) {
if (js_obj instanceof PyProxy) {
if (
js_obj instanceof PyProxy ||
(typeof js_obj === "function" && "_ref" in js_obj) ||
js_obj instanceof PyProxyThenable
) {
const kind = PROXY_KIND_JS_OBJECT;
const id = proxy_js_ref.length;
proxy_js_ref[id] = js_obj;
@ -197,6 +217,7 @@ function proxy_convert_mp_to_js_obj_jsside(value) {
obj = (...args) => {
return proxy_call_python(id, args);
};
obj._ref = id;
} else if (kind === PROXY_KIND_MP_GENERATOR) {
obj = new PyProxyThenable(id);
} else {

Wyświetl plik

@ -0,0 +1,24 @@
# The asyncio package is built from the standard implementation but with the
# core scheduler replaced with a custom scheduler that uses the JavaScript
# runtime (with setTimeout an Promise's) to contrtol the scheduling.
package(
"asyncio",
(
"event.py",
"funcs.py",
"lock.py",
),
base_path="$(MPY_DIR)/extmod",
opt=3,
)
package(
"asyncio",
(
"__init__.py",
"core.py",
),
base_path="$(PORT_DIR)",
opt=3,
)

Wyświetl plik

@ -1,3 +1,5 @@
include("$(PORT_DIR)/variants/manifest.py")
require("abc")
require("base64")
require("collections")

Wyświetl plik

@ -29,6 +29,7 @@
// This header file contains definitions to dynamically implement the static
// MicroPython runtime API defined in py/obj.h and py/runtime.h.
#include "py/binary.h"
#include "py/nativeglue.h"
#include "py/objfun.h"
#include "py/objstr.h"
@ -184,6 +185,10 @@ static inline void *mp_obj_malloc_helper_dyn(size_t num_bytes, const mp_obj_type
/******************************************************************************/
// General runtime functions
#define mp_binary_get_size(struct_type, val_type, palign) (mp_fun_table.binary_get_size((struct_type), (val_type), (palign)))
#define mp_binary_get_val_array(typecode, p, index) (mp_fun_table.binary_get_val_array((typecode), (p), (index)))
#define mp_binary_set_val_array(typecode, p, index, val_in) (mp_fun_table.binary_set_val_array((typecode), (p), (index), (val_in)))
#define mp_load_name(qst) (mp_fun_table.load_name((qst)))
#define mp_load_global(qst) (mp_fun_table.load_global((qst)))
#define mp_load_attr(base, attr) (mp_fun_table.load_attr((base), (attr)))

Wyświetl plik

@ -223,11 +223,11 @@ static_qstr_list = [
"zip",
]
# Additional QSTRs that must have index <255 because they are stored in
# `mp_binary_op_method_name` and `mp_unary_op_method_name` (see py/objtype.c).
# Additional QSTRs that must have index <255 because they are stored as `byte` values.
# These are not part of the .mpy compatibility list, but we place them in the
# fixed unsorted pool (i.e. QDEF0) to ensure their indices are small.
operator_qstr_list = {
unsorted_qstr_list = {
# From py/objtype.c: used in the `mp_binary_op_method_name` and `mp_unary_op_method_name` tables.
"__bool__",
"__pos__",
"__neg__",
@ -286,6 +286,13 @@ operator_qstr_list = {
"__get__",
"__set__",
"__delete__",
# From py/scope.c: used in `scope_simple_name_table` table.
# Note: "<module>" is already in `static_qstr_list`.
"<lambda>",
"<listcomp>",
"<dictcomp>",
"<setcomp>",
"<genexpr>",
}
@ -404,10 +411,10 @@ def print_qstr_data(qcfgs, qstrs):
print("QDEF0(MP_QSTR_%s, %s)" % (qstr_escape(qstr), qbytes))
# add remaining qstrs to the sorted (by value) pool (unless they're in
# operator_qstr_list, in which case add them to the unsorted pool)
# unsorted_qstr_list, in which case add them to the unsorted pool)
for ident, qstr in sorted(qstrs.values(), key=lambda x: x[1]):
qbytes = make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr)
pool = 0 if qstr in operator_qstr_list else 1
pool = 0 if qstr in unsorted_qstr_list else 1
print("QDEF%d(MP_QSTR_%s, %s)" % (pool, ident, qbytes))

Wyświetl plik

@ -587,6 +587,12 @@
/*****************************************************************************/
/* Python internal features */
// Use a special long jump in nlrthumb.c, which may be necessary if nlr.o and
// nlrthumb.o are linked far apart from each other.
#ifndef MICROPY_NLR_THUMB_USE_LONG_JUMP
#define MICROPY_NLR_THUMB_USE_LONG_JUMP (0)
#endif
// Whether to enable import of external modules
// When disabled, only importing of built-in modules is supported
// When enabled, a port must implement mp_import_stat (among other things)

Wyświetl plik

@ -29,6 +29,7 @@
#include <string.h>
#include <assert.h>
#include "py/binary.h"
#include "py/runtime.h"
#include "py/smallint.h"
#include "py/nativeglue.h"
@ -330,6 +331,9 @@ const mp_fun_table_t mp_fun_table = {
mp_obj_get_float_to_d,
mp_get_buffer,
mp_get_stream_raise,
mp_binary_get_size,
mp_binary_get_val_array,
mp_binary_set_val_array,
&mp_plat_print,
&mp_type_type,
&mp_type_str,

Wyświetl plik

@ -156,7 +156,12 @@ typedef struct _mp_fun_table_t {
double (*obj_get_float_to_d)(mp_obj_t o);
bool (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);
const mp_stream_p_t *(*get_stream_raise)(mp_obj_t self_in, int flags);
size_t (*binary_get_size)(char struct_type, char val_type, size_t *palign);
mp_obj_t (*binary_get_val_array)(char typecode, void *p, size_t index);
void (*binary_set_val_array)(char typecode, void *p, size_t index, mp_obj_t val_in);
const mp_print_t *plat_print;
// The following entries start at index 70 and are referenced by tools-mpy_ld.py,
// see constant MP_FUN_TABLE_MP_TYPE_TYPE_OFFSET.
const mp_obj_type_t *type_type;
const mp_obj_type_t *type_str;
const mp_obj_type_t *type_list;

Wyświetl plik

@ -75,7 +75,7 @@ NORETURN void nlr_jump(void *val) {
"ret \n"
:
: "r" (top)
:
: "memory"
);
MP_UNREACHABLE

Wyświetl plik

@ -78,7 +78,7 @@ NORETURN void nlr_jump(void *val) {
"nop \n"
:
: "r" (top)
:
: "memory"
);
MP_UNREACHABLE
}

Wyświetl plik

@ -114,7 +114,7 @@ NORETURN void nlr_jump(void *val) {
"blr ;"
:
: "r" (&top->regs)
:
: "memory"
);
MP_UNREACHABLE;
@ -203,7 +203,7 @@ NORETURN void nlr_jump(void *val) {
"blr ;"
:
: "r" (&top->regs)
:
: "memory"
);
MP_UNREACHABLE;

Wyświetl plik

@ -38,6 +38,14 @@
__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
// If you get a linker error here, indicating that a relocation doesn't
// fit, try the following (in that order):
//
// 1. Ensure that nlr.o nlrthumb.o are linked closely together, i.e.
// there aren't too many other files between them in the linker list
// (PY_CORE_O_BASENAME in py/py.mk)
// 2. Set -DMICROPY_NLR_THUMB_USE_LONG_JUMP=1 during the build
//
__asm volatile (
"str r4, [r0, #12] \n" // store r4 into nlr_buf
"str r5, [r0, #16] \n" // store r5 into nlr_buf
@ -71,7 +79,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
"str lr, [r0, #8] \n" // store lr into nlr_buf
#endif
#if !defined(__thumb2__)
#if MICROPY_NLR_THUMB_USE_LONG_JUMP
"ldr r1, nlr_push_tail_var \n"
"bx r1 \n" // do the rest in C
".align 2 \n"
@ -132,7 +140,7 @@ NORETURN void nlr_jump(void *val) {
"bx lr \n" // return
: // output operands
: "r" (top) // input operands
: // clobbered registers
: "memory" // clobbered registers
);
MP_UNREACHABLE

Wyświetl plik

@ -123,7 +123,7 @@ NORETURN void nlr_jump(void *val) {
"ret \n" // return
: // output operands
: "r" (top) // input operands
: // clobbered registers
: "memory" // clobbered registers
);
MP_UNREACHABLE

Some files were not shown because too many files have changed in this diff Show More