kopia lustrzana https://github.com/micropython/micropython
Merge branch 'master' of https://github.com/kldonnelly/micropython
commit
d5197af43b
|
@ -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 }}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
---------
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */ \
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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) },
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 89424753e18ed58b7d8041085c9d2e1d162f09ca
|
|
@ -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
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
#define MICROPY_HW_BOARD_NAME "Trinket M0"
|
||||
#define MICROPY_HW_MCU_NAME "SAMD21E18A"
|
||||
|
||||
#define MICROPY_HW_DFLL_USB_SYNC (1)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
------------------
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"'
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"'
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"'
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
|
@ -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()
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
)
|
|
@ -1,3 +1,5 @@
|
|||
include("$(PORT_DIR)/variants/manifest.py")
|
||||
|
||||
require("abc")
|
||||
require("base64")
|
||||
require("collections")
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -75,7 +75,7 @@ NORETURN void nlr_jump(void *val) {
|
|||
"ret \n"
|
||||
:
|
||||
: "r" (top)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
|
||||
MP_UNREACHABLE
|
||||
|
|
|
@ -78,7 +78,7 @@ NORETURN void nlr_jump(void *val) {
|
|||
"nop \n"
|
||||
:
|
||||
: "r" (top)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
MP_UNREACHABLE
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Ładowanie…
Reference in New Issue