Merge remote-tracking branch 'upstream/master' into dev-8.0
This commit is contained in:
commit
6d7ec6e424
24
.github/workflows/ports_javascript.yml
vendored
Normal file
24
.github/workflows/ports_javascript.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: javascript port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'ports/javascript/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_javascript_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_javascript_build
|
||||
- name: Run tests
|
||||
run: source tools/ci.sh && ci_javascript_run_tests
|
||||
65
LICENSE
65
LICENSE
@ -19,3 +19,68 @@ 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.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Unless specified otherwise (see below), the above license and copyright applies
|
||||
to all files in this repository.
|
||||
|
||||
Individual files may include additional copyright holders.
|
||||
|
||||
The various ports of MicroPython may include third-party software that is
|
||||
licensed under different terms. These licenses are summarised in the tree
|
||||
below, please refer to these files and directories for further license and
|
||||
copyright information. Note that (L)GPL-licensed code listed below is only
|
||||
used during the build process and is not part of the compiled source code.
|
||||
|
||||
/ (MIT)
|
||||
/drivers
|
||||
/cc3000 (BSD-3-clause)
|
||||
/cc3100 (BSD-3-clause)
|
||||
/wiznet5k (BSD-3-clause)
|
||||
/extmod
|
||||
/crypto-algorithms (NONE)
|
||||
/re15 (BSD-3-clause)
|
||||
/uzlib (Zlib)
|
||||
/lib
|
||||
/asf4 (Apache-2.0)
|
||||
/axtls (BSD-3-clause)
|
||||
/config
|
||||
/scripts
|
||||
/config (GPL-2.0-or-later)
|
||||
/Rules.mak (GPL-2.0)
|
||||
/berkeley-db-1xx (BSD-4-clause)
|
||||
/btstack (See btstack/LICENSE)
|
||||
/cmsis (BSD-3-clause)
|
||||
/libhydrogen (ISC)
|
||||
/littlefs (BSD-3-clause)
|
||||
/lwip (BSD-3-clause)
|
||||
/mynewt-nimble (Apache-2.0)
|
||||
/nrfx (BSD-3-clause)
|
||||
/nxp_driver (BSD-3-Clause)
|
||||
/oofatfs (BSD-1-clause)
|
||||
/pico-sdk (BSD-3-clause)
|
||||
/stm32lib (BSD-3-clause)
|
||||
/tinytest (BSD-3-clause)
|
||||
/tinyusb (MIT)
|
||||
/logo (uses OFL-1.1)
|
||||
/ports
|
||||
/cc3200
|
||||
/hal (BSD-3-clause)
|
||||
/simplelink (BSD-3-clause)
|
||||
/FreeRTOS (GPL-2.0 with FreeRTOS exception)
|
||||
/stm32
|
||||
/usbd*.c (MCD-ST Liberty SW License Agreement V2)
|
||||
/stm32_it.* (MIT + BSD-3-clause)
|
||||
/system_stm32*.c (MIT + BSD-3-clause)
|
||||
/boards
|
||||
/startup_stm32*.s (BSD-3-clause)
|
||||
/*/stm32*.h (BSD-3-clause)
|
||||
/usbdev (MCD-ST Liberty SW License Agreement V2)
|
||||
/usbhost (MCD-ST Liberty SW License Agreement V2)
|
||||
/teensy
|
||||
/core (PJRC.COM)
|
||||
/zephyr
|
||||
/src (Apache-2.0)
|
||||
/tools
|
||||
/dfu.py (LGPL-3.0-only)
|
||||
|
||||
@ -66,7 +66,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'MicroPython'
|
||||
copyright = '2014-2021, Damien P. George, Paul Sokolovsky, and contributors'
|
||||
copyright = '- The MicroPython Documentation is Copyright © 2014-2021, Damien P. George, Paul Sokolovsky, and contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
@ -74,7 +74,7 @@ copyright = '2014-2021, Damien P. George, Paul Sokolovsky, and contributors'
|
||||
#
|
||||
# We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags"
|
||||
# breakdown, so use the same version identifier for both to avoid confusion.
|
||||
version = release = '1.15'
|
||||
version = release = '1.16'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@ -102,6 +102,14 @@ Once the network is established the :mod:`socket <usocket>` module can be used
|
||||
to create and use TCP/UDP sockets as usual, and the ``urequests`` module for
|
||||
convenient HTTP requests.
|
||||
|
||||
After a call to ``wlan.connect()``, the device will by default retry to connect
|
||||
**forever**, even when the authentication failed or no AP is in range.
|
||||
``wlan.status()`` will return ``network.STAT_CONNECTING`` in this state until a
|
||||
connection succeeds or the interface gets disabled. This can be changed by
|
||||
calling ``wlan.config(reconnects=n)``, where n are the number of desired reconnect
|
||||
attempts (0 means it won't retry, -1 will restore the default behaviour of trying
|
||||
to reconnect forever).
|
||||
|
||||
Delay and timing
|
||||
----------------
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@ and time.
|
||||
Example usage::
|
||||
|
||||
rtc = machine.RTC()
|
||||
rtc.init((2014, 5, 1, 4, 13, 0, 0, 0))
|
||||
print(rtc.now())
|
||||
rtc.datetime((2020, 1, 21, 2, 10, 32, 36, 0))
|
||||
print(rtc.datetime())
|
||||
|
||||
|
||||
Constructors
|
||||
@ -24,6 +24,20 @@ Constructors
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: RTC.datetime([datetimetuple])
|
||||
|
||||
Get or set the date and time of the RTC.
|
||||
|
||||
With no arguments, this method returns an 8-tuple with the current
|
||||
date and time. With 1 argument (being an 8-tuple) it sets the date
|
||||
and time.
|
||||
|
||||
The 8-tuple has the following format:
|
||||
|
||||
(year, month, day, weekday, hours, minutes, seconds, subseconds)
|
||||
|
||||
The meaning of the ``subseconds`` field is hardware dependent.
|
||||
|
||||
.. method:: RTC.init(datetime)
|
||||
|
||||
Initialise the RTC. Datetime is a tuple of the form:
|
||||
|
||||
@ -129,4 +129,5 @@ Methods
|
||||
authmode Authentication mode supported (enumeration, see module constants)
|
||||
password Access password (string)
|
||||
dhcp_hostname The DHCP hostname to use
|
||||
reconnects Number of reconnect attempts to make (integer, 0=none, -1=unlimited)
|
||||
============= ===========
|
||||
|
||||
@ -109,6 +109,16 @@ Methods
|
||||
|
||||
Return value: number of bytes sent.
|
||||
|
||||
.. method:: USB_VCP.irq(handler=None, trigger=IRQ_RX, hard=False)
|
||||
|
||||
Register *handler* to be called whenever an event specified by *trigger*
|
||||
occurs. The *handler* function must take exactly one argument, which will
|
||||
be the USB VCP object. Pass in ``None`` to disable the callback.
|
||||
|
||||
Valid values for *trigger* are:
|
||||
|
||||
- ``USB_VCP.IRQ_RX``: new data is available for reading from the USB VCP object.
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
@ -117,3 +127,7 @@ Constants
|
||||
USB_VCP.CTS
|
||||
|
||||
to select the flow control type.
|
||||
|
||||
.. data:: USB_VCP.IRQ_RX
|
||||
|
||||
IRQ trigger values for :meth:`USB_VCP.irq`.
|
||||
|
||||
@ -240,6 +240,14 @@ TCP stream connections
|
||||
|
||||
This is a coroutine.
|
||||
|
||||
.. method:: Stream.readinto(buf)
|
||||
|
||||
Read up to n bytes into *buf* with n being equal to the length of *buf*.
|
||||
|
||||
Return the number of bytes read into *buf*.
|
||||
|
||||
This is a coroutine, and a MicroPython extension.
|
||||
|
||||
.. method:: Stream.readline()
|
||||
|
||||
Read a line and return it.
|
||||
|
||||
@ -202,7 +202,7 @@ See :ref:`machine.RTC <machine.RTC>` ::
|
||||
from machine import RTC
|
||||
|
||||
rtc = RTC()
|
||||
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time
|
||||
rtc.datetime((2017, 8, 23, 2, 12, 48, 0, 0)) # set a specific date and time
|
||||
rtc.datetime() # get date and time
|
||||
|
||||
WDT (Watchdog timer)
|
||||
|
||||
@ -15,6 +15,7 @@ SET_PAGE_ADDR = const(0x22)
|
||||
SET_DISP_START_LINE = const(0x40)
|
||||
SET_SEG_REMAP = const(0xA0)
|
||||
SET_MUX_RATIO = const(0xA8)
|
||||
SET_IREF_SELECT = const(0xAD)
|
||||
SET_COM_OUT_DIR = const(0xC0)
|
||||
SET_DISP_OFFSET = const(0xD3)
|
||||
SET_COM_PIN_CFG = const(0xDA)
|
||||
@ -63,6 +64,8 @@ class SSD1306(framebuf.FrameBuffer):
|
||||
0xFF, # maximum
|
||||
SET_ENTIRE_ON, # output follows RAM contents
|
||||
SET_NORM_INV, # not inverted
|
||||
SET_IREF_SELECT,
|
||||
0x30, # enable internal IREF during display on
|
||||
# charge pump
|
||||
SET_CHARGE_PUMP,
|
||||
0x10 if self.external_vcc else 0x14,
|
||||
@ -92,10 +95,11 @@ class SSD1306(framebuf.FrameBuffer):
|
||||
def show(self):
|
||||
x0 = 0
|
||||
x1 = self.width - 1
|
||||
if self.width == 64:
|
||||
# displays with width of 64 pixels are shifted by 32
|
||||
x0 += 32
|
||||
x1 += 32
|
||||
if self.width != 128:
|
||||
# narrow displays use centred columns
|
||||
col_offset = (128 - self.width) // 2
|
||||
x0 += col_offset
|
||||
x1 += col_offset
|
||||
self.write_cmd(SET_COL_ADDR)
|
||||
self.write_cmd(x0)
|
||||
self.write_cmd(x1)
|
||||
|
||||
@ -30,7 +30,6 @@ INC += -I$(BTSTACK_DIR)/3rd-party/yxml
|
||||
SRC_BTSTACK = \
|
||||
$(addprefix lib/btstack/src/, $(SRC_FILES)) \
|
||||
$(addprefix lib/btstack/src/ble/, $(filter-out %_tlv.c, $(SRC_BLE_FILES))) \
|
||||
lib/btstack/platform/embedded/btstack_run_loop_embedded.c
|
||||
|
||||
ifeq ($(MICROPY_BLUETOOTH_BTSTACK_USB),1)
|
||||
ifeq ($(MICROPY_BLUETOOTH_BTSTACK_H4),1)
|
||||
|
||||
@ -86,6 +86,7 @@ STATIC int btstack_uart_open(void) {
|
||||
|
||||
STATIC int btstack_uart_close(void) {
|
||||
mp_bluetooth_hci_controller_deinit();
|
||||
mp_bluetooth_hci_uart_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -849,6 +849,11 @@ int mp_bluetooth_gap_set_device_name(const uint8_t *buf, size_t len) {
|
||||
|
||||
int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) {
|
||||
DEBUG_printf("mp_bluetooth_gap_advertise_start\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
uint16_t adv_int_min = interval_us / 625;
|
||||
uint16_t adv_int_max = interval_us / 625;
|
||||
uint8_t adv_type = connectable ? 0 : 2;
|
||||
@ -885,6 +890,11 @@ int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, cons
|
||||
|
||||
void mp_bluetooth_gap_advertise_stop(void) {
|
||||
DEBUG_printf("mp_bluetooth_gap_advertise_stop\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gap_advertisements_enable(false);
|
||||
MP_STATE_PORT(bluetooth_btstack_root_pointers)->adv_data_alloc = 0;
|
||||
MP_STATE_PORT(bluetooth_btstack_root_pointers)->adv_data = NULL;
|
||||
@ -892,6 +902,11 @@ void mp_bluetooth_gap_advertise_stop(void) {
|
||||
|
||||
int mp_bluetooth_gatts_register_service_begin(bool append) {
|
||||
DEBUG_printf("mp_bluetooth_gatts_register_service_begin\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
if (!append) {
|
||||
// This will reset the DB.
|
||||
// Becase the DB is statically allocated, there's no problem with just re-initing it.
|
||||
@ -1064,16 +1079,27 @@ int mp_bluetooth_gatts_register_service_end(void) {
|
||||
|
||||
int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len) {
|
||||
DEBUG_printf("mp_bluetooth_gatts_read\n");
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, value, value_len);
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len) {
|
||||
DEBUG_printf("mp_bluetooth_gatts_write\n");
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, value, value_len);
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle) {
|
||||
DEBUG_printf("mp_bluetooth_gatts_notify\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
// Note: btstack doesn't appear to support sending a notification without a value, so include the stored value.
|
||||
uint8_t *data = NULL;
|
||||
size_t len = 0;
|
||||
@ -1084,6 +1110,10 @@ int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle) {
|
||||
int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len) {
|
||||
DEBUG_printf("mp_bluetooth_gatts_notify_send\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
// Attempt to send immediately. If it succeeds, btstack will copy the buffer.
|
||||
MICROPY_PY_BLUETOOTH_ENTER
|
||||
int err = att_server_notify(conn_handle, value_handle, value, value_len);
|
||||
@ -1110,6 +1140,10 @@ int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle,
|
||||
int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) {
|
||||
DEBUG_printf("mp_bluetooth_gatts_indicate\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
uint8_t *data = NULL;
|
||||
size_t len = 0;
|
||||
mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, &data, &len);
|
||||
@ -1142,6 +1176,9 @@ int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) {
|
||||
|
||||
int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append) {
|
||||
DEBUG_printf("mp_bluetooth_gatts_set_buffer\n");
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return mp_bluetooth_gatts_db_resize(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, len, append);
|
||||
}
|
||||
|
||||
@ -1165,6 +1202,9 @@ int mp_bluetooth_set_preferred_mtu(uint16_t mtu) {
|
||||
|
||||
int mp_bluetooth_gap_disconnect(uint16_t conn_handle) {
|
||||
DEBUG_printf("mp_bluetooth_gap_disconnect\n");
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
gap_disconnect(conn_handle);
|
||||
return 0;
|
||||
}
|
||||
@ -1195,6 +1235,10 @@ STATIC void scan_duration_timeout_handler(btstack_timer_source_t *ds) {
|
||||
int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_t window_us, bool active_scan) {
|
||||
DEBUG_printf("mp_bluetooth_gap_scan_start\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
if (duration_ms > 0) {
|
||||
btstack_run_loop_set_timer(&scan_duration_timeout, duration_ms);
|
||||
btstack_run_loop_set_timer_handler(&scan_duration_timeout, scan_duration_timeout_handler);
|
||||
@ -1209,6 +1253,9 @@ int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_
|
||||
|
||||
int mp_bluetooth_gap_scan_stop(void) {
|
||||
DEBUG_printf("mp_bluetooth_gap_scan_stop\n");
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
btstack_run_loop_remove_timer(&scan_duration_timeout);
|
||||
gap_stop_scan();
|
||||
mp_bluetooth_gap_on_scan_complete();
|
||||
@ -1240,6 +1287,11 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
|
||||
|
||||
int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid) {
|
||||
DEBUG_printf("mp_bluetooth_gattc_discover_primary_services\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
uint8_t err;
|
||||
if (uuid) {
|
||||
if (uuid->type == MP_BLUETOOTH_UUID_TYPE_16) {
|
||||
@ -1260,6 +1312,11 @@ int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_
|
||||
|
||||
int mp_bluetooth_gattc_discover_characteristics(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, const mp_obj_bluetooth_uuid_t *uuid) {
|
||||
DEBUG_printf("mp_bluetooth_gattc_discover_characteristics\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
gatt_client_service_t service = {
|
||||
// Only start/end handles needed for gatt_client_discover_characteristics_for_service.
|
||||
.start_group_handle = start_handle,
|
||||
@ -1287,6 +1344,11 @@ int mp_bluetooth_gattc_discover_characteristics(uint16_t conn_handle, uint16_t s
|
||||
|
||||
int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle) {
|
||||
DEBUG_printf("mp_bluetooth_gattc_discover_descriptors\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
gatt_client_characteristic_t characteristic = {
|
||||
// Only start/end handles needed for gatt_client_discover_characteristic_descriptors.
|
||||
.start_handle = start_handle,
|
||||
@ -1301,12 +1363,19 @@ int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start
|
||||
|
||||
int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle) {
|
||||
DEBUG_printf("mp_bluetooth_gattc_read\n");
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return btstack_error_to_errno(gatt_client_read_value_of_characteristic_using_value_handle(&btstack_packet_handler_read, conn_handle, value_handle));
|
||||
}
|
||||
|
||||
int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len, unsigned int mode) {
|
||||
DEBUG_printf("mp_bluetooth_gattc_write\n");
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
// We should be distinguishing between gatt_client_write_value_of_characteristic vs
|
||||
// gatt_client_write_characteristic_descriptor_using_descriptor_handle.
|
||||
// However both are implemented using send_gatt_write_attribute_value_request under the hood,
|
||||
|
||||
@ -46,7 +46,7 @@ static void sha256_transform(CRYAL_SHA256_CTX *ctx, const BYTE data[])
|
||||
WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
|
||||
|
||||
for (i = 0, j = 0; i < 16; ++i, j += 4)
|
||||
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
|
||||
m[i] = ((uint32_t)data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
|
||||
for ( ; i < 64; ++i)
|
||||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||||
|
||||
|
||||
@ -31,12 +31,22 @@
|
||||
|
||||
#if MICROPY_PY_UASYNCIO
|
||||
|
||||
// Used when task cannot be guaranteed to be non-NULL.
|
||||
#define TASK_PAIRHEAP(task) ((task) ? &(task)->pairheap : NULL)
|
||||
|
||||
#define TASK_STATE_RUNNING_NOT_WAITED_ON (mp_const_true)
|
||||
#define TASK_STATE_DONE_NOT_WAITED_ON (mp_const_none)
|
||||
#define TASK_STATE_DONE_WAS_WAITED_ON (mp_const_false)
|
||||
|
||||
#define TASK_IS_DONE(task) ( \
|
||||
(task)->state == TASK_STATE_DONE_NOT_WAITED_ON \
|
||||
|| (task)->state == TASK_STATE_DONE_WAS_WAITED_ON)
|
||||
|
||||
typedef struct _mp_obj_task_t {
|
||||
mp_pairheap_t pairheap;
|
||||
mp_obj_t coro;
|
||||
mp_obj_t data;
|
||||
mp_obj_t waiting;
|
||||
|
||||
mp_obj_t state;
|
||||
mp_obj_t ph_key;
|
||||
} mp_obj_task_t;
|
||||
|
||||
@ -103,7 +113,7 @@ STATIC mp_obj_t task_queue_push_sorted(size_t n_args, const mp_obj_t *args) {
|
||||
assert(mp_obj_is_small_int(args[2]));
|
||||
task->ph_key = args[2];
|
||||
}
|
||||
self->heap = (mp_obj_task_t *)mp_pairheap_push(task_lt, &self->heap->pairheap, &task->pairheap);
|
||||
self->heap = (mp_obj_task_t *)mp_pairheap_push(task_lt, TASK_PAIRHEAP(self->heap), TASK_PAIRHEAP(task));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(task_queue_push_sorted_obj, 2, 3, task_queue_push_sorted);
|
||||
@ -146,9 +156,6 @@ STATIC const mp_obj_type_t task_queue_type = {
|
||||
/******************************************************************************/
|
||||
// Task class
|
||||
|
||||
// For efficiency, the task object is stored to the coro entry when the task is done.
|
||||
#define TASK_IS_DONE(task) ((task)->coro == MP_OBJ_FROM_PTR(task))
|
||||
|
||||
// This is the core uasyncio context with cur_task, _task_queue and CancelledError.
|
||||
STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL;
|
||||
|
||||
@ -159,7 +166,7 @@ STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
|
||||
mp_pairheap_init_node(task_lt, &self->pairheap);
|
||||
self->coro = args[0];
|
||||
self->data = mp_const_none;
|
||||
self->waiting = mp_const_none;
|
||||
self->state = TASK_STATE_RUNNING_NOT_WAITED_ON;
|
||||
self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
|
||||
if (n_args == 2) {
|
||||
uasyncio_context = args[1];
|
||||
@ -218,24 +225,6 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
|
||||
|
||||
STATIC mp_obj_t task_throw(mp_obj_t self_in, mp_obj_t value_in) {
|
||||
// This task raised an exception which was uncaught; handle that now.
|
||||
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
// Set the data because it was cleared by the main scheduling loop.
|
||||
self->data = value_in;
|
||||
if (self->waiting == mp_const_none) {
|
||||
// Nothing await'ed on the task so call the exception handler.
|
||||
mp_obj_t _exc_context = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__exc_context));
|
||||
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_exception), value_in);
|
||||
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_future), self_in);
|
||||
mp_obj_t Loop = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_Loop));
|
||||
mp_obj_t call_exception_handler = mp_load_attr(Loop, MP_QSTR_call_exception_handler);
|
||||
mp_call_function_1(call_exception_handler, _exc_context);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_throw_obj, task_throw);
|
||||
|
||||
STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (dest[0] == MP_OBJ_NULL) {
|
||||
@ -244,32 +233,24 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
dest[0] = self->coro;
|
||||
} else if (attr == MP_QSTR_data) {
|
||||
dest[0] = self->data;
|
||||
} else if (attr == MP_QSTR_waiting) {
|
||||
if (self->waiting != mp_const_none && self->waiting != mp_const_false) {
|
||||
dest[0] = self->waiting;
|
||||
}
|
||||
} else if (attr == MP_QSTR_state) {
|
||||
dest[0] = self->state;
|
||||
} else if (attr == MP_QSTR_done) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(&task_done_obj);
|
||||
dest[1] = self_in;
|
||||
} else if (attr == MP_QSTR_cancel) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj);
|
||||
dest[1] = self_in;
|
||||
} else if (attr == MP_QSTR_throw) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(&task_throw_obj);
|
||||
dest[1] = self_in;
|
||||
} else if (attr == MP_QSTR_ph_key) {
|
||||
dest[0] = self->ph_key;
|
||||
}
|
||||
} else if (dest[1] != MP_OBJ_NULL) {
|
||||
// Store
|
||||
if (attr == MP_QSTR_coro) {
|
||||
self->coro = dest[1];
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
} else if (attr == MP_QSTR_data) {
|
||||
if (attr == MP_QSTR_data) {
|
||||
self->data = dest[1];
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
} else if (attr == MP_QSTR_waiting) {
|
||||
self->waiting = dest[1];
|
||||
} else if (attr == MP_QSTR_state) {
|
||||
self->state = dest[1];
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
@ -278,15 +259,12 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
|
||||
(void)iter_buf;
|
||||
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (self->waiting == mp_const_none) {
|
||||
// The is the first access of the "waiting" entry.
|
||||
if (TASK_IS_DONE(self)) {
|
||||
// Signal that the completed-task has been await'ed on.
|
||||
self->waiting = mp_const_false;
|
||||
} else {
|
||||
// Lazily allocate the waiting queue.
|
||||
self->waiting = task_queue_make_new(&task_queue_type, 0, 0, NULL);
|
||||
}
|
||||
if (TASK_IS_DONE(self)) {
|
||||
// Signal that the completed-task has been await'ed on.
|
||||
self->state = TASK_STATE_DONE_WAS_WAITED_ON;
|
||||
} else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
|
||||
// Allocate the waiting queue.
|
||||
self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
|
||||
}
|
||||
return self_in;
|
||||
}
|
||||
@ -299,7 +277,7 @@ STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
|
||||
} else {
|
||||
// Put calling task on waiting queue.
|
||||
mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
|
||||
mp_obj_t args[2] = { self->waiting, cur_task };
|
||||
mp_obj_t args[2] = { self->state, cur_task };
|
||||
task_queue_push_sorted(2, args);
|
||||
// Set calling task's data to this task that it waits on, to double-link it.
|
||||
((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
|
||||
|
||||
@ -1030,7 +1030,6 @@ int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle,
|
||||
if (om == NULL) {
|
||||
return MP_ENOMEM;
|
||||
}
|
||||
// TODO: check that notify_custom takes ownership of om, if not os_mbuf_free_chain(om).
|
||||
return ble_hs_err_to_errno(ble_gattc_notify_custom(conn_handle, value_handle, om));
|
||||
}
|
||||
|
||||
|
||||
@ -175,6 +175,10 @@ def run_until_complete(main_task=None):
|
||||
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:
|
||||
@ -185,22 +189,32 @@ def run_until_complete(main_task=None):
|
||||
if isinstance(er, StopIteration):
|
||||
return er.value
|
||||
raise er
|
||||
# Schedule any other tasks waiting on the completion of this task
|
||||
waiting = False
|
||||
if hasattr(t, "waiting"):
|
||||
while t.waiting.peek():
|
||||
_task_queue.push_head(t.waiting.pop_head())
|
||||
waiting = True
|
||||
t.waiting = None # Free waiting queue head
|
||||
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_head(t)
|
||||
# Indicate task is done by setting coro to the task object itself
|
||||
t.coro = t
|
||||
# Save return value of coro to pass up to caller
|
||||
t.data = er
|
||||
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
|
||||
else:
|
||||
# Schedule any other tasks waiting on the completion of this task.
|
||||
while t.state.peek():
|
||||
_task_queue.push_head(t.state.pop_head())
|
||||
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_head(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.
|
||||
_exc_context["exception"] = exc
|
||||
_exc_context["future"] = t
|
||||
Loop.call_exception_handler(_exc_context)
|
||||
|
||||
|
||||
# Create a new task from a coroutine and run it until it finishes
|
||||
|
||||
@ -30,6 +30,10 @@ class Stream:
|
||||
yield core._io_queue.queue_read(self.s)
|
||||
return self.s.read(n)
|
||||
|
||||
async def readinto(self, buf):
|
||||
yield core._io_queue.queue_read(self.s)
|
||||
return self.s.readinto(buf)
|
||||
|
||||
async def readexactly(self, n):
|
||||
r = b""
|
||||
while n:
|
||||
@ -103,15 +107,7 @@ class Server:
|
||||
async def wait_closed(self):
|
||||
await self.task
|
||||
|
||||
async def _serve(self, cb, host, port, backlog):
|
||||
import usocket as socket
|
||||
|
||||
ai = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
|
||||
s = socket.socket()
|
||||
s.setblocking(False)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
s.bind(ai[-1])
|
||||
s.listen(backlog)
|
||||
async def _serve(self, s, cb):
|
||||
# Accept incoming connections
|
||||
while True:
|
||||
try:
|
||||
@ -133,9 +129,20 @@ class Server:
|
||||
# Helper function to start a TCP stream server, running as a new task
|
||||
# TODO could use an accept-callback on socket read activity instead of creating a task
|
||||
async def start_server(cb, host, port, backlog=5):
|
||||
s = Server()
|
||||
s.task = core.create_task(s._serve(cb, host, port, backlog))
|
||||
return s
|
||||
import usocket as socket
|
||||
|
||||
# Create and bind server socket.
|
||||
host = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
|
||||
s = socket.socket()
|
||||
s.setblocking(False)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
s.bind(host[-1])
|
||||
s.listen(backlog)
|
||||
|
||||
# Create and return server object and task.
|
||||
srv = Server()
|
||||
srv.task = core.create_task(srv._serve(s, cb))
|
||||
return srv
|
||||
|
||||
|
||||
################################################################################
|
||||
|
||||
@ -123,6 +123,7 @@ class Task:
|
||||
def __init__(self, coro, globals=None):
|
||||
self.coro = coro # Coroutine of this Task
|
||||
self.data = None # General data for queue it is waiting on
|
||||
self.state = True # None, False, True or a TaskQueue instance
|
||||
self.ph_key = 0 # Pairing heap
|
||||
self.ph_child = None # Paring heap
|
||||
self.ph_child_last = None # Paring heap
|
||||
@ -130,30 +131,30 @@ class Task:
|
||||
self.ph_rightmost_parent = None # Paring heap
|
||||
|
||||
def __iter__(self):
|
||||
if self.coro is self:
|
||||
# Signal that the completed-task has been await'ed on.
|
||||
self.waiting = None
|
||||
elif not hasattr(self, "waiting"):
|
||||
# Lazily allocated head of linked list of Tasks waiting on completion of this task.
|
||||
self.waiting = TaskQueue()
|
||||
if not self.state:
|
||||
# Task finished, signal that is has been await'ed on.
|
||||
self.state = False
|
||||
elif self.state is True:
|
||||
# Allocated head of linked list of Tasks waiting on completion of this task.
|
||||
self.state = TaskQueue()
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if self.coro is self:
|
||||
if not self.state:
|
||||
# Task finished, raise return value to caller so it can continue.
|
||||
raise self.data
|
||||
else:
|
||||
# Put calling task on waiting queue.
|
||||
self.waiting.push_head(core.cur_task)
|
||||
self.state.push_head(core.cur_task)
|
||||
# Set calling task's data to this task that it waits on, to double-link it.
|
||||
core.cur_task.data = self
|
||||
|
||||
def done(self):
|
||||
return self.coro is self
|
||||
return not self.state
|
||||
|
||||
def cancel(self):
|
||||
# Check if task is already finished.
|
||||
if self.coro is self:
|
||||
if not self.state:
|
||||
return False
|
||||
# Can't cancel self (not supported yet).
|
||||
if self is core.cur_task:
|
||||
@ -172,13 +173,3 @@ class Task:
|
||||
core._task_queue.push_head(self)
|
||||
self.data = core.CancelledError
|
||||
return True
|
||||
|
||||
def throw(self, value):
|
||||
# This task raised an exception which was uncaught; handle that now.
|
||||
# Set the data because it was cleared by the main scheduling loop.
|
||||
self.data = value
|
||||
if not hasattr(self, "waiting"):
|
||||
# Nothing await'ed on the task so call the exception handler.
|
||||
core._exc_context["exception"] = value
|
||||
core._exc_context["future"] = self
|
||||
core.Loop.call_exception_handler(core._exc_context)
|
||||
|
||||
@ -213,3 +213,10 @@ mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday,
|
||||
}
|
||||
return timeutils_seconds_since_2000(year, month, mday, hours, minutes, seconds);
|
||||
}
|
||||
|
||||
// Calculate the weekday from the date.
|
||||
// The result is zero based with 0 = Monday.
|
||||
// by Michael Keith and Tom Craver, 1990.
|
||||
int timeutils_calc_weekday(int y, int m, int d) {
|
||||
return ((d += m < 3 ? y-- : y - 2, 23 * m / 9 + d + 4 + y / 4 - y / 100 + y / 400) + 6) % 7;
|
||||
}
|
||||
|
||||
@ -100,4 +100,6 @@ static inline int64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_197
|
||||
|
||||
#endif
|
||||
|
||||
int timeutils_calc_weekday(int y, int m, int d);
|
||||
|
||||
#endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H
|
||||
|
||||
@ -62,7 +62,9 @@
|
||||
#define MICROPY_READER_POSIX (1)
|
||||
#define MICROPY_ENABLE_RUNTIME (0)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#endif
|
||||
#define MICROPY_HELPER_LEXER_UNIX (1)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (1)
|
||||
|
||||
@ -50,10 +50,19 @@ To check out a copy of the IDF use git clone:
|
||||
$ git clone -b v4.0.2 --recursive https://github.com/espressif/esp-idf.git
|
||||
```
|
||||
|
||||
You can replace `v4.0.2` with `v4.1.1` or any other supported version.
|
||||
You can replace `v4.0.2` with `v4.1.1` or `v4.2` or any other supported version.
|
||||
(You don't need a full recursive clone; see the `ci_esp32_setup` function in
|
||||
`tools/ci.sh` in this repository for more detailed set-up commands.)
|
||||
|
||||
If you already have a copy of the IDF then checkout a version compatible with
|
||||
MicroPython and update the submodules using:
|
||||
|
||||
```bash
|
||||
$ cd esp-idf
|
||||
$ git checkout v4.2
|
||||
$ git submodule update --init --recursive
|
||||
```
|
||||
|
||||
After you've cloned and checked out the IDF to the correct version, run the
|
||||
`install.sh` script:
|
||||
|
||||
|
||||
@ -31,6 +31,10 @@ CONFIG_IDLE_TASK_STACK_SIZE=4096
|
||||
# Power Management
|
||||
CONFIG_PM_ENABLE=y
|
||||
|
||||
# Memory protection
|
||||
# This is required to allow allocating IRAM
|
||||
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n
|
||||
|
||||
# FreeRTOS
|
||||
CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
|
||||
@ -218,6 +218,10 @@ STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *pos_args,
|
||||
mp_obj_get_array(pulses, &pulses_length, &pulses_ptr);
|
||||
|
||||
mp_uint_t num_items = (pulses_length / 2) + (pulses_length % 2);
|
||||
if (self->loop_en && num_items > 63) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("too many pulses for loop"));
|
||||
}
|
||||
|
||||
if (num_items > self->num_items) {
|
||||
self->items = (rmt_item32_t *)m_realloc(self->items, num_items * sizeof(rmt_item32_t *));
|
||||
self->num_items = num_items;
|
||||
@ -241,12 +245,12 @@ STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *pos_args,
|
||||
check_esp_err(rmt_set_tx_loop_mode(self->channel_id, false));
|
||||
}
|
||||
check_esp_err(rmt_wait_tx_done(self->channel_id, portMAX_DELAY));
|
||||
check_esp_err(rmt_set_tx_intr_en(self->channel_id, false));
|
||||
}
|
||||
|
||||
check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false /* non-blocking */));
|
||||
|
||||
if (self->loop_en) {
|
||||
check_esp_err(rmt_set_tx_intr_en(self->channel_id, false));
|
||||
check_esp_err(rmt_set_tx_loop_mode(self->channel_id, true));
|
||||
}
|
||||
|
||||
|
||||
@ -411,6 +411,32 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_
|
||||
}
|
||||
self->base.type = &machine_hw_spi_type;
|
||||
|
||||
int8_t sck, mosi, miso;
|
||||
|
||||
if (args[ARG_sck].u_obj == MP_OBJ_NULL) {
|
||||
sck = default_pins->sck;
|
||||
} else if (args[ARG_sck].u_obj == mp_const_none) {
|
||||
sck = -1;
|
||||
} else {
|
||||
sck = machine_pin_get_id(args[ARG_sck].u_obj);
|
||||
}
|
||||
|
||||
if (args[ARG_mosi].u_obj == MP_OBJ_NULL) {
|
||||
mosi = default_pins->mosi;
|
||||
} else if (args[ARG_mosi].u_obj == mp_const_none) {
|
||||
mosi = -1;
|
||||
} else {
|
||||
mosi = machine_pin_get_id(args[ARG_mosi].u_obj);
|
||||
}
|
||||
|
||||
if (args[ARG_miso].u_obj == MP_OBJ_NULL) {
|
||||
miso = default_pins->miso;
|
||||
} else if (args[ARG_miso].u_obj == mp_const_none) {
|
||||
miso = -1;
|
||||
} else {
|
||||
miso = machine_pin_get_id(args[ARG_miso].u_obj);
|
||||
}
|
||||
|
||||
machine_hw_spi_init_internal(
|
||||
self,
|
||||
args[ARG_id].u_int,
|
||||
@ -419,9 +445,9 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_
|
||||
args[ARG_phase].u_int,
|
||||
args[ARG_bits].u_int,
|
||||
args[ARG_firstbit].u_int,
|
||||
args[ARG_sck].u_obj == MP_OBJ_NULL ? default_pins->sck : machine_pin_get_id(args[ARG_sck].u_obj),
|
||||
args[ARG_mosi].u_obj == MP_OBJ_NULL ? default_pins->mosi : machine_pin_get_id(args[ARG_mosi].u_obj),
|
||||
args[ARG_miso].u_obj == MP_OBJ_NULL ? default_pins->miso : machine_pin_get_id(args[ARG_miso].u_obj));
|
||||
sck,
|
||||
mosi,
|
||||
miso);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
@ -256,7 +256,14 @@ STATIC mp_obj_t sd_deinit(mp_obj_t self_in) {
|
||||
DEBUG_printf("De-init host\n");
|
||||
|
||||
if (self->flags & SDCARD_CARD_FLAGS_HOST_INIT_DONE) {
|
||||
self->host.deinit();
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
|
||||
if (self->host.flags & SDMMC_HOST_FLAG_DEINIT_ARG) {
|
||||
self->host.deinit_p(self->host.slot);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
self->host.deinit();
|
||||
}
|
||||
self->flags &= ~SDCARD_CARD_FLAGS_HOST_INIT_DONE;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
# Set location of base MicroPython directory.
|
||||
get_filename_component(MICROPY_DIR ${PROJECT_DIR}/../.. ABSOLUTE)
|
||||
if(NOT MICROPY_DIR)
|
||||
get_filename_component(MICROPY_DIR ${PROJECT_DIR}/../.. ABSOLUTE)
|
||||
endif()
|
||||
|
||||
# Include core source components.
|
||||
include(${MICROPY_DIR}/py/py.cmake)
|
||||
|
||||
@ -1,19 +1,44 @@
|
||||
import sys
|
||||
# Combine bootloader, partition table and application into a final binary.
|
||||
|
||||
import os, sys
|
||||
|
||||
sys.path.append(os.getenv("IDF_PATH") + "/components/partition_table")
|
||||
|
||||
import gen_esp32part
|
||||
|
||||
OFFSET_BOOTLOADER = 0x1000
|
||||
OFFSET_PARTITIONS = 0x8000
|
||||
OFFSET_APPLICATION = 0x10000
|
||||
|
||||
|
||||
def load_partition_table(filename):
|
||||
with open(filename, "rb") as f:
|
||||
return gen_esp32part.PartitionTable.from_binary(f.read())
|
||||
|
||||
|
||||
partition_table = load_partition_table(sys.argv[2])
|
||||
|
||||
max_size_bootloader = OFFSET_PARTITIONS - OFFSET_BOOTLOADER
|
||||
max_size_partitions = 0
|
||||
offset_application = 0
|
||||
max_size_application = 0
|
||||
|
||||
for part in partition_table:
|
||||
if part.name == "nvs":
|
||||
max_size_partitions = part.offset - OFFSET_PARTITIONS
|
||||
elif part.type == gen_esp32part.APP_TYPE and offset_application == 0:
|
||||
offset_application = part.offset
|
||||
max_size_application = part.size
|
||||
|
||||
files_in = [
|
||||
("bootloader", OFFSET_BOOTLOADER, sys.argv[1]),
|
||||
("partitions", OFFSET_PARTITIONS, sys.argv[2]),
|
||||
("application", OFFSET_APPLICATION, sys.argv[3]),
|
||||
("bootloader", OFFSET_BOOTLOADER, max_size_bootloader, sys.argv[1]),
|
||||
("partitions", OFFSET_PARTITIONS, max_size_partitions, sys.argv[2]),
|
||||
("application", offset_application, max_size_application, sys.argv[3]),
|
||||
]
|
||||
file_out = sys.argv[4]
|
||||
|
||||
cur_offset = OFFSET_BOOTLOADER
|
||||
with open(file_out, "wb") as fout:
|
||||
for name, offset, file_in in files_in:
|
||||
for name, offset, max_size, file_in in files_in:
|
||||
assert offset >= cur_offset
|
||||
fout.write(b"\xff" * (offset - cur_offset))
|
||||
cur_offset = offset
|
||||
@ -21,5 +46,14 @@ with open(file_out, "wb") as fout:
|
||||
data = fin.read()
|
||||
fout.write(data)
|
||||
cur_offset += len(data)
|
||||
print("%-12s% 8d" % (name, len(data)))
|
||||
print("%-12s% 8d" % ("total", cur_offset))
|
||||
print(
|
||||
"%-12s@0x%06x % 8d (% 8d remaining)"
|
||||
% (name, offset, len(data), max_size - len(data))
|
||||
)
|
||||
if len(data) > max_size:
|
||||
print(
|
||||
"ERROR: %s overflows allocated space of %d bytes by %d bytes"
|
||||
% (name, max_size, len(data) - max_size)
|
||||
)
|
||||
sys.exit(1)
|
||||
print("%-22s% 8d" % ("total", cur_offset))
|
||||
|
||||
@ -142,12 +142,16 @@ static uint8_t wifi_sta_disconn_reason = 0;
|
||||
static bool mdns_initialised = false;
|
||||
#endif
|
||||
|
||||
static uint8_t conf_wifi_sta_reconnects = 0;
|
||||
static uint8_t wifi_sta_reconnects;
|
||||
|
||||
// This function is called by the system-event task and so runs in a different
|
||||
// thread to the main MicroPython task. It must not raise any Python exceptions.
|
||||
static esp_err_t event_handler(void *ctx, system_event_t *event) {
|
||||
switch (event->event_id) {
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
ESP_LOGI("wifi", "STA_START");
|
||||
wifi_sta_reconnects = 0;
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_CONNECTED:
|
||||
ESP_LOGI("network", "CONNECTED");
|
||||
@ -199,15 +203,23 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) {
|
||||
wifi_sta_connected = false;
|
||||
if (wifi_sta_connect_requested) {
|
||||
wifi_mode_t mode;
|
||||
if (esp_wifi_get_mode(&mode) == ESP_OK) {
|
||||
if (mode & WIFI_MODE_STA) {
|
||||
// STA is active so attempt to reconnect.
|
||||
esp_err_t e = esp_wifi_connect();
|
||||
if (e != ESP_OK) {
|
||||
ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e);
|
||||
}
|
||||
if (esp_wifi_get_mode(&mode) != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
if (!(mode & WIFI_MODE_STA)) {
|
||||
break;
|
||||
}
|
||||
if (conf_wifi_sta_reconnects) {
|
||||
ESP_LOGI("wifi", "reconnect counter=%d, max=%d",
|
||||
wifi_sta_reconnects, conf_wifi_sta_reconnects);
|
||||
if (++wifi_sta_reconnects >= conf_wifi_sta_reconnects) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
esp_err_t e = esp_wifi_connect();
|
||||
if (e != ESP_OK) {
|
||||
ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -361,6 +373,7 @@ STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
|
||||
ESP_EXCEPTIONS(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config));
|
||||
}
|
||||
|
||||
wifi_sta_reconnects = 0;
|
||||
// connect to the WiFi AP
|
||||
MP_THREAD_GIL_EXIT();
|
||||
ESP_EXCEPTIONS(esp_wifi_connect());
|
||||
@ -395,7 +408,9 @@ STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) {
|
||||
if (wifi_sta_connected) {
|
||||
// Happy path, connected with IP
|
||||
return MP_OBJ_NEW_SMALL_INT(STAT_GOT_IP);
|
||||
} else if (wifi_sta_connect_requested) {
|
||||
} else if (wifi_sta_connect_requested
|
||||
&& (conf_wifi_sta_reconnects == 0
|
||||
|| wifi_sta_reconnects < conf_wifi_sta_reconnects)) {
|
||||
// No connection or error, but is requested = Still connecting
|
||||
return MP_OBJ_NEW_SMALL_INT(STAT_CONNECTING);
|
||||
} else if (wifi_sta_disconn_reason == 0) {
|
||||
@ -633,6 +648,14 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
|
||||
cfg.ap.max_connection = mp_obj_get_int(kwargs->table[i].value);
|
||||
break;
|
||||
}
|
||||
case QS(MP_QSTR_reconnects): {
|
||||
int reconnects = mp_obj_get_int(kwargs->table[i].value);
|
||||
req_if = WIFI_IF_STA;
|
||||
// parameter reconnects == -1 means to retry forever.
|
||||
// here means conf_wifi_sta_reconnects == 0 to retry forever.
|
||||
conf_wifi_sta_reconnects = (reconnects == -1) ? 0 : reconnects + 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
@ -666,13 +689,6 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
|
||||
case WIFI_IF_STA:
|
||||
ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac));
|
||||
return mp_obj_new_bytes(mac, sizeof(mac));
|
||||
|
||||
#if !MICROPY_ESP_IDF_4
|
||||
case ESP_IF_ETH:
|
||||
esp_eth_get_mac(mac);
|
||||
return mp_obj_new_bytes(mac, sizeof(mac));
|
||||
#endif
|
||||
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
@ -711,6 +727,11 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
|
||||
val = MP_OBJ_NEW_SMALL_INT(cfg.ap.max_connection);
|
||||
break;
|
||||
}
|
||||
case QS(MP_QSTR_reconnects):
|
||||
req_if = WIFI_IF_STA;
|
||||
int rec = conf_wifi_sta_reconnects - 1;
|
||||
val = MP_OBJ_NEW_SMALL_INT(rec);
|
||||
break;
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
@ -753,12 +774,12 @@ STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode);
|
||||
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_initialize_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
|
||||
#if !MICROPY_ESP_IDF_4
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
|
||||
{ MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_PPP), MP_ROM_PTR(&ppp_make_new_obj) },
|
||||
@ -784,18 +805,22 @@ STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) },
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_TLK110), MP_ROM_INT(PHY_TLK110) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_IP101), MP_ROM_INT(PHY_IP101) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_RTL8201), MP_ROM_INT(PHY_RTL8201) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_DP83848), MP_ROM_INT(PHY_DP83848) },
|
||||
#if ESP_IDF_VERSION_MINOR >= 3
|
||||
// PHY_KSZ8041 is new in ESP-IDF v4.3
|
||||
{ MP_ROM_QSTR(MP_QSTR_PHY_KSZ8041), MP_ROM_INT(PHY_KSZ8041) },
|
||||
#endif
|
||||
|
||||
// ETH Clock modes from ESP-IDF
|
||||
#if !MICROPY_ESP_IDF_4
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO0_IN), MP_ROM_INT(ETH_CLOCK_GPIO0_IN) },
|
||||
// Disabled at Aug 22nd 2018, reenabled Jan 28th 2019 in ESP-IDF
|
||||
// Because we use older SDK, it's currently disabled
|
||||
// { MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO0_OUT), MP_ROM_INT(ETH_CLOCK_GPIO0_OUT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO16_OUT), MP_ROM_INT(ETH_CLOCK_GPIO16_OUT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_CLOCK_GPIO17_OUT), MP_ROM_INT(ETH_CLOCK_GPIO17_OUT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_INITIALIZED), MP_ROM_INT(ETH_INITIALIZED)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_STARTED), MP_ROM_INT(ETH_STARTED)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_STOPPED), MP_ROM_INT(ETH_STOPPED)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_CONNECTED), MP_ROM_INT(ETH_CONNECTED)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_DISCONNECTED), MP_ROM_INT(ETH_DISCONNECTED)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_ETH_GOT_IP), MP_ROM_INT(ETH_GOT_IP)},
|
||||
#endif
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STAT_IDLE)},
|
||||
|
||||
@ -26,7 +26,8 @@
|
||||
#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H
|
||||
#define MICROPY_INCLUDED_ESP32_MODNETWORK_H
|
||||
|
||||
enum { PHY_LAN8720, PHY_TLK110, PHY_IP101 };
|
||||
enum { PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041 };
|
||||
enum { ETH_INITIALIZED, ETH_STARTED, ETH_STOPPED, ETH_CONNECTED, ETH_DISCONNECTED, ETH_GOT_IP };
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(ppp_make_new_obj);
|
||||
|
||||
@ -15,6 +15,9 @@ class NeoPixel:
|
||||
self.pin.init(pin.OUT)
|
||||
self.timing = timing
|
||||
|
||||
def __len__(self):
|
||||
return self.n
|
||||
|
||||
def __setitem__(self, index, val):
|
||||
offset = index * self.bpp
|
||||
for i in range(self.bpp):
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
|
||||
* Copyright (c) 2021 "Tobias Eydam" <tobiaseydam@hotmail.com>
|
||||
*
|
||||
* Based on the ESP IDF example code which is Public Domain / CC0
|
||||
*
|
||||
@ -26,15 +27,19 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if !MICROPY_ESP_IDF_4
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
#include "eth_phy/phy.h"
|
||||
#include "eth_phy/phy_tlk110.h"
|
||||
#include "eth_phy/phy_lan8720.h"
|
||||
#include "eth_phy/phy_ip101.h"
|
||||
#include "tcpip_adapter.h"
|
||||
#include "esp_idf_version.h"
|
||||
|
||||
// LAN only for ESP32 (not ESP32S2) and only for ESP-IDF v4.1 and higher
|
||||
#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
|
||||
|
||||
#include "esp_eth.h"
|
||||
#include "esp_eth_mac.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
#include "modnetwork.h"
|
||||
|
||||
@ -48,47 +53,43 @@ typedef struct _lan_if_obj_t {
|
||||
int8_t phy_power_pin;
|
||||
uint8_t phy_addr;
|
||||
uint8_t phy_type;
|
||||
eth_phy_check_link_func link_func;
|
||||
eth_phy_power_enable_func power_func;
|
||||
esp_eth_phy_t *phy;
|
||||
esp_netif_t *eth_netif;
|
||||
esp_eth_handle_t eth_handle;
|
||||
} lan_if_obj_t;
|
||||
|
||||
const mp_obj_type_t lan_if_type;
|
||||
STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false};
|
||||
STATIC uint8_t eth_status = 0;
|
||||
|
||||
STATIC void phy_power_enable(bool enable) {
|
||||
lan_if_obj_t *self = &lan_obj;
|
||||
|
||||
if (self->phy_power_pin != -1) {
|
||||
|
||||
if (!enable) {
|
||||
// Do the PHY-specific power_enable(false) function before powering down
|
||||
self->power_func(false);
|
||||
}
|
||||
|
||||
gpio_pad_select_gpio(self->phy_power_pin);
|
||||
gpio_set_direction(self->phy_power_pin, GPIO_MODE_OUTPUT);
|
||||
if (enable) {
|
||||
gpio_set_level(self->phy_power_pin, 1);
|
||||
} else {
|
||||
gpio_set_level(self->phy_power_pin, 0);
|
||||
}
|
||||
|
||||
// Allow the power up/down to take effect, min 300us
|
||||
vTaskDelay(1);
|
||||
|
||||
if (enable) {
|
||||
// Run the PHY-specific power on operations now the PHY has power
|
||||
self->power_func(true);
|
||||
}
|
||||
static void eth_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data) {
|
||||
switch (event_id) {
|
||||
case ETHERNET_EVENT_CONNECTED:
|
||||
eth_status = ETH_CONNECTED;
|
||||
ESP_LOGI("ethernet", "Ethernet Link Up");
|
||||
break;
|
||||
case ETHERNET_EVENT_DISCONNECTED:
|
||||
eth_status = ETH_DISCONNECTED;
|
||||
ESP_LOGI("ethernet", "Ethernet Link Down");
|
||||
break;
|
||||
case ETHERNET_EVENT_START:
|
||||
eth_status = ETH_STARTED;
|
||||
ESP_LOGI("ethernet", "Ethernet Started");
|
||||
break;
|
||||
case ETHERNET_EVENT_STOP:
|
||||
eth_status = ETH_STOPPED;
|
||||
ESP_LOGI("ethernet", "Ethernet Stopped");
|
||||
break;
|
||||
case IP_EVENT_ETH_GOT_IP:
|
||||
eth_status = ETH_GOT_IP;
|
||||
ESP_LOGI("ethernet", "Ethernet Got IP");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void init_lan_rmii() {
|
||||
lan_if_obj_t *self = &lan_obj;
|
||||
phy_rmii_configure_data_interface_pins();
|
||||
phy_rmii_smi_configure_pins(self->mdc_pin, self->mdio_pin);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
lan_if_obj_t *self = &lan_obj;
|
||||
|
||||
@ -96,7 +97,7 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||
return MP_OBJ_FROM_PTR(&lan_obj);
|
||||
}
|
||||
|
||||
enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type, ARG_clock_mode };
|
||||
enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
@ -104,7 +105,6 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||
{ MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_clock_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
@ -123,56 +123,91 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||
if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid phy address"));
|
||||
}
|
||||
self->phy_addr = args[ARG_phy_addr].u_int;
|
||||
|
||||
if (args[ARG_phy_type].u_int != PHY_LAN8720 &&
|
||||
args[ARG_phy_type].u_int != PHY_TLK110 &&
|
||||
args[ARG_phy_type].u_int != PHY_IP101) {
|
||||
args[ARG_phy_type].u_int != PHY_IP101 &&
|
||||
args[ARG_phy_type].u_int != PHY_RTL8201 &&
|
||||
#if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
|
||||
args[ARG_phy_type].u_int != PHY_KSZ8041 &&
|
||||
#endif
|
||||
args[ARG_phy_type].u_int != PHY_DP83848) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid phy type"));
|
||||
}
|
||||
|
||||
if (args[ARG_clock_mode].u_int != -1 &&
|
||||
args[ARG_clock_mode].u_int != ETH_CLOCK_GPIO0_IN &&
|
||||
// Disabled due ESP-IDF (see modnetwork.c note)
|
||||
// args[ARG_clock_mode].u_int != ETH_CLOCK_GPIO0_OUT &&
|
||||
args[ARG_clock_mode].u_int != ETH_CLOCK_GPIO16_OUT &&
|
||||
args[ARG_clock_mode].u_int != ETH_CLOCK_GPIO17_OUT) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid clock mode"));
|
||||
}
|
||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
|
||||
mac_config.smi_mdc_gpio_num = self->mdc_pin;
|
||||
mac_config.smi_mdio_gpio_num = self->mdio_pin;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
|
||||
|
||||
eth_config_t config;
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
|
||||
phy_config.phy_addr = self->phy_addr;
|
||||
phy_config.reset_gpio_num = self->phy_power_pin;
|
||||
self->phy = NULL;
|
||||
|
||||
switch (args[ARG_phy_type].u_int) {
|
||||
case PHY_TLK110:
|
||||
config = phy_tlk110_default_ethernet_config;
|
||||
break;
|
||||
case PHY_LAN8720:
|
||||
config = phy_lan8720_default_ethernet_config;
|
||||
self->phy = esp_eth_phy_new_lan8720(&phy_config);
|
||||
break;
|
||||
case PHY_IP101:
|
||||
config = phy_ip101_default_ethernet_config;
|
||||
self->phy = esp_eth_phy_new_ip101(&phy_config);
|
||||
break;
|
||||
case PHY_RTL8201:
|
||||
self->phy = esp_eth_phy_new_rtl8201(&phy_config);
|
||||
break;
|
||||
case PHY_DP83848:
|
||||
self->phy = esp_eth_phy_new_dp83848(&phy_config);
|
||||
break;
|
||||
case PHY_KSZ8041:
|
||||
#if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
|
||||
self->phy = esp_eth_phy_new_ksz8041(&phy_config);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("unknown phy"));
|
||||
}
|
||||
|
||||
self->link_func = config.phy_check_link;
|
||||
|
||||
// Replace default power func with our own
|
||||
self->power_func = config.phy_power_enable;
|
||||
config.phy_power_enable = phy_power_enable;
|
||||
|
||||
config.phy_addr = args[ARG_phy_addr].u_int;
|
||||
config.gpio_config = init_lan_rmii;
|
||||
config.tcpip_input = tcpip_adapter_eth_input;
|
||||
|
||||
if (args[ARG_clock_mode].u_int != -1) {
|
||||
config.clock_mode = args[ARG_clock_mode].u_int;
|
||||
if (esp_netif_init() != ESP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_netif_init failed"));
|
||||
}
|
||||
|
||||
if (esp_eth_init(&config) == ESP_OK) {
|
||||
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
|
||||
self->eth_netif = esp_netif_new(&cfg);
|
||||
|
||||
if (esp_eth_set_default_handlers(self->eth_netif) != ESP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_eth_set_default_handlers failed (invalid parameter)"));
|
||||
}
|
||||
|
||||
if (esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL) != ESP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_event_handler_register failed"));
|
||||
}
|
||||
|
||||
if (esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL) != ESP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_event_handler_register failed"));
|
||||
}
|
||||
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, self->phy);
|
||||
|
||||
esp_err_t esp_err = esp_eth_driver_install(&config, &self->eth_handle);
|
||||
if (esp_err == ESP_OK) {
|
||||
self->active = false;
|
||||
self->initialized = true;
|
||||
} else {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_eth_init() failed"));
|
||||
if (esp_err == ESP_ERR_INVALID_ARG) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_eth_driver_install failed with invalid argument"));
|
||||
} else if (esp_err == ESP_ERR_NO_MEM) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_eth_driver_install failed with no memory for driver"));
|
||||
} else {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_eth_driver_install failed"));
|
||||
}
|
||||
}
|
||||
|
||||
if (esp_netif_attach(self->eth_netif, esp_eth_new_netif_glue(self->eth_handle)) != ESP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_netif_attach failed"));
|
||||
}
|
||||
|
||||
eth_status = ETH_INITIALIZED;
|
||||
|
||||
return MP_OBJ_FROM_PTR(&lan_obj);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(get_lan_obj, 0, get_lan);
|
||||
@ -182,37 +217,87 @@ STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) {
|
||||
|
||||
if (n_args > 1) {
|
||||
if (mp_obj_is_true(args[1])) {
|
||||
self->active = (esp_eth_enable() == ESP_OK);
|
||||
self->active = (esp_eth_start(self->eth_handle) == ESP_OK);
|
||||
if (!self->active) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("ethernet enable failed"));
|
||||
}
|
||||
} else {
|
||||
self->active = !(esp_eth_disable() == ESP_OK);
|
||||
self->active = !(esp_eth_stop(self->eth_handle) == ESP_OK);
|
||||
if (self->active) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("ethernet disable failed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mp_obj_new_bool(self->active);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lan_active_obj, 1, 2, lan_active);
|
||||
|
||||
STATIC mp_obj_t lan_status(mp_obj_t self_in) {
|
||||
return mp_const_none;
|
||||
return MP_OBJ_NEW_SMALL_INT(eth_status);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_status_obj, lan_status);
|
||||
|
||||
STATIC mp_obj_t lan_isconnected(mp_obj_t self_in) {
|
||||
lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return self->active ? mp_obj_new_bool(self->link_func()) : mp_const_false;
|
||||
return self->active ? mp_obj_new_bool(self->phy->get_link(self->phy) == ETH_LINK_UP) : mp_const_false;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_isconnected_obj, lan_isconnected);
|
||||
|
||||
STATIC mp_obj_t lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
if (n_args != 1 && kwargs->used != 0) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed"));
|
||||
}
|
||||
lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
|
||||
|
||||
if (kwargs->used != 0) {
|
||||
|
||||
for (size_t i = 0; i < kwargs->alloc; i++) {
|
||||
if (mp_map_slot_is_filled(kwargs, i)) {
|
||||
switch ((uintptr_t)kwargs->table[i].key) {
|
||||
case QS(MP_QSTR_mac): {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
|
||||
if (bufinfo.len != 6) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length"));
|
||||
}
|
||||
esp_eth_ioctl(self->eth_handle, ETH_CMD_S_MAC_ADDR, bufinfo.buf);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
if (n_args != 2) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("can query only one param"));
|
||||
}
|
||||
|
||||
mp_obj_t val = mp_const_none;
|
||||
|
||||
switch ((uintptr_t)args[1]) {
|
||||
case QS(MP_QSTR_mac): {
|
||||
uint8_t mac[6];
|
||||
esp_eth_ioctl(self->eth_handle, ETH_CMD_G_MAC_ADDR, mac);
|
||||
return mp_obj_new_bytes(mac, sizeof(mac));
|
||||
}
|
||||
default:
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(lan_config_obj, 1, lan_config);
|
||||
|
||||
STATIC const mp_rom_map_elem_t lan_if_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&lan_active_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&lan_isconnected_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&lan_config_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
|
||||
};
|
||||
|
||||
@ -224,4 +309,4 @@ const mp_obj_type_t lan_if_type = {
|
||||
.locals_dict = (mp_obj_dict_t *)&lan_if_locals_dict,
|
||||
};
|
||||
|
||||
#endif // !MICROPY_ESP_IDF_4
|
||||
#endif
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# Notes: the offset of the partition table itself is set in
|
||||
# $ESPIDF/components/partition_table/Kconfig.projbuild and the
|
||||
# offset of the factory/ota_0 partition is set in makeimg.py
|
||||
# $IDF_PATH/components/partition_table/Kconfig.projbuild.
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
# Notes: the offset of the partition table itself is set in
|
||||
# $ESPIDF/components/partition_table/Kconfig.projbuild and the
|
||||
# offset of the factory/ota_0 partition is set in makeimg.py
|
||||
# $IDF_PATH/components/partition_table/Kconfig.projbuild.
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 0x110000,
|
||||
vfs, data, fat, 0x120000, 0xA0000,
|
||||
factory, app, factory, 0x10000, 0x160000,
|
||||
vfs, data, fat, 0x170000, 0x50000,
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
# Partition table for MicroPython with OTA support using 4MB flash
|
||||
# Notes: the offset of the partition table itself is set in
|
||||
# $ESPIDF/components/partition_table/Kconfig.projbuild and the
|
||||
# offset of the factory/ota_0 partition is set in makeimg.py
|
||||
# $IDF_PATH/components/partition_table/Kconfig.projbuild.
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x4000,
|
||||
otadata, data, ota, 0xd000, 0x2000,
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
# Notes: the offset of the partition table itself is set in
|
||||
# $ESPIDF/components/partition_table/Kconfig.projbuild and the
|
||||
# offset of the factory/ota_0 partition is set in makeimg.py
|
||||
# $IDF_PATH/components/partition_table/Kconfig.projbuild.
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
|
||||
|
3
ports/esp8266/boards/GENERIC_512K/_boot.py
Normal file
3
ports/esp8266/boards/GENERIC_512K/_boot.py
Normal file
@ -0,0 +1,3 @@
|
||||
import gc
|
||||
|
||||
gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4)
|
||||
@ -1,3 +1,4 @@
|
||||
freeze("$(BOARD_DIR)", "_boot.py", opt=3)
|
||||
freeze("$(PORT_DIR)/modules", ("apa102.py", "neopixel.py", "ntptime.py", "port_diag.py"))
|
||||
freeze("$(MPY_DIR)/drivers/dht", "dht.py")
|
||||
freeze("$(MPY_DIR)/drivers/onewire")
|
||||
|
||||
@ -237,7 +237,7 @@ STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
|
||||
while (esp_scan_list != NULL) {
|
||||
// our esp_scan_cb is called via ets_loop_iter so it's safe to set the
|
||||
// esp_scan_list variable to NULL without disabling interrupts
|
||||
if (MP_STATE_VM(mp_pending_exception) != NULL) {
|
||||
if (MP_STATE_THREAD(mp_pending_exception) != NULL) {
|
||||
esp_scan_list = NULL;
|
||||
mp_handle_pending(true);
|
||||
}
|
||||
|
||||
@ -15,6 +15,9 @@ class NeoPixel:
|
||||
self.pin.init(pin.OUT)
|
||||
self.timing = timing
|
||||
|
||||
def __len__(self):
|
||||
return self.n
|
||||
|
||||
def __setitem__(self, index, val):
|
||||
offset = index * self.bpp
|
||||
for i in range(self.bpp):
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
--- JSBackend.cpp 2018-01-10 16:35:07.331418145 +1100
|
||||
+++ JSBackend_mp_js.cpp 2018-01-10 16:40:04.804633134 +1100
|
||||
@@ -4280,6 +4280,7 @@
|
||||
|
||||
void JSWriter::calculateNativizedVars(const Function *F) {
|
||||
NativizedVars.clear();
|
||||
+ return;
|
||||
|
||||
for (Function::const_iterator I = F->begin(), BE = F->end(); I != BE; ++I) {
|
||||
auto BI = &*I;
|
||||
@ -6,24 +6,16 @@ QSTR_DEFS = qstrdefsport.h
|
||||
|
||||
include $(TOP)/py/py.mk
|
||||
|
||||
CC = emcc -g4
|
||||
LD = emcc -g4
|
||||
CC = emcc
|
||||
LD = emcc
|
||||
|
||||
INC += -I.
|
||||
INC += -I$(TOP)
|
||||
INC += -I$(BUILD)
|
||||
|
||||
CPP = clang -E
|
||||
|
||||
ifdef EMSCRIPTEN
|
||||
CPP += -isystem $(EMSCRIPTEN)/system/include/libc -cxx-isystem $(EMSCRIPTEN)/system/include/libcxx
|
||||
endif
|
||||
|
||||
CFLAGS = -m32 -Wall -Werror -Wdouble-promotion -Wfloat-conversion $(INC) -std=c99 $(COPT)
|
||||
LDFLAGS = -m32 -Wl,-Map=$@.map,--cref -Wl,--gc-sections
|
||||
|
||||
CFLAGS += -O0 -DNDEBUG
|
||||
CFLAGS += -fdata-sections -ffunction-sections
|
||||
CFLAGS += -std=c99 -Wall -Werror -Wdouble-promotion -Wfloat-conversion
|
||||
CFLAGS += -O3 -DNDEBUG
|
||||
CFLAGS += $(INC)
|
||||
|
||||
ifneq ($(FROZEN_MPY_DIR),)
|
||||
# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and
|
||||
@ -46,12 +38,12 @@ SRC_C = \
|
||||
|
||||
SRC_QSTR += $(SRC_C)
|
||||
|
||||
OBJ =
|
||||
OBJ = $(PY_O)
|
||||
OBJ += $(PY_O)
|
||||
OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
||||
|
||||
JSFLAGS = -O0 -s EXPORTED_FUNCTIONS="['_mp_js_init', '_mp_js_init_repl', '_mp_js_do_str', '_mp_js_process_char', '_mp_hal_get_interrupt_char', '_mp_sched_keyboard_interrupt']" -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']" -s "BINARYEN_TRAP_MODE='clamp'" --memory-init-file 0 --js-library library.js
|
||||
JSFLAGS += -s ASYNCIFY
|
||||
JSFLAGS += -s EXPORTED_FUNCTIONS="['_mp_js_init', '_mp_js_init_repl', '_mp_js_do_str', '_mp_js_process_char', '_mp_hal_get_interrupt_char', '_mp_sched_keyboard_interrupt']" -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']" -s --memory-init-file 0 --js-library library.js
|
||||
|
||||
all: $(BUILD)/micropython.js
|
||||
|
||||
@ -65,6 +57,6 @@ min: $(BUILD)/micropython.js
|
||||
|
||||
test: $(BUILD)/micropython.js $(TOP)/tests/run-tests.py
|
||||
$(eval DIRNAME=ports/$(notdir $(CURDIR)))
|
||||
cd $(TOP)/tests && MICROPY_MICROPYTHON=../ports/javascript/node_run.sh ./run-tests.py
|
||||
cd $(TOP)/tests && MICROPY_MICROPYTHON=../ports/javascript/node_run.sh ./run-tests.py -j1
|
||||
|
||||
include $(TOP)/py/mkrules.mk
|
||||
|
||||
@ -7,17 +7,7 @@ Dependencies
|
||||
------------
|
||||
|
||||
Building micropython.js bears the same requirements as the standard MicroPython
|
||||
ports with the addition of Emscripten (and uglify-js for the minified file).
|
||||
|
||||
A standard installation of Emscripten should provide functional code, however
|
||||
if memory errors are encountered it may be worthwhile to modify the tool.
|
||||
`emscripten-fastcomp/lib/Target/JSBackend.cpp` may require the minor fix
|
||||
found in JSBackend.patch. This patch attempts to address situations where
|
||||
C code running through Emscripten is denied access to Javascript variables
|
||||
leading to false-positives in the MicroPython garbage collector as variables
|
||||
with pointers exclusively in Javascript will be erased prematurely.
|
||||
Refer to Emscripten documentation for instructions on building Emscripten
|
||||
from source.
|
||||
ports with the addition of Emscripten (and uglify-js for the minified file).
|
||||
|
||||
Build instructions
|
||||
------------------
|
||||
@ -39,15 +29,15 @@ Access the repl with:
|
||||
|
||||
Stack size may be modified using:
|
||||
|
||||
$ node build/micropython.js -X stack=64K
|
||||
$ node build/micropython.js -X stack=64K
|
||||
|
||||
Where stack size may be represented in Bytes, KiB or MiB.
|
||||
|
||||
MicroPython scripts may be executed using:
|
||||
|
||||
$ node build/micropython.js hello.py
|
||||
$ node build/micropython.js hello.py
|
||||
|
||||
Alternatively micropython.js may by accessed by other javascript programs in node
|
||||
Alternatively micropython.js may by accessed by other javascript programs in node
|
||||
using the require command and the general API outlined below. For example:
|
||||
|
||||
```javascript
|
||||
@ -85,7 +75,7 @@ demonstrates basic functionality:
|
||||
```
|
||||
|
||||
MicroPython code execution will suspend the browser so be sure to atomize usage
|
||||
within this environment. Unfortunately interrupts have not been implemented for the
|
||||
within this environment. Unfortunately interrupts have not been implemented for the
|
||||
browser.
|
||||
|
||||
Testing
|
||||
@ -124,5 +114,5 @@ the repl.
|
||||
mp_js_process_char(char)
|
||||
```
|
||||
|
||||
Input character into MicroPython repl. `char` must be of type `number`. This
|
||||
Input character into MicroPython repl. `char` must be of type `number`. This
|
||||
will execute MicroPython code when necessary.
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George and 2017, 2018 Rami Ali
|
||||
* Copyright (c) 2013-2021 Damien P. George and 2017, 2018 Rami Ali
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -36,6 +36,7 @@
|
||||
#include "py/mperrno.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
|
||||
#include "emscripten.h"
|
||||
#include "library.h"
|
||||
|
||||
#if MICROPY_ENABLE_COMPILER
|
||||
@ -70,8 +71,6 @@ int do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *stack_top;
|
||||
|
||||
int mp_js_do_str(const char *code) {
|
||||
return do_str(code, MP_PARSE_FILE_INPUT);
|
||||
}
|
||||
@ -81,9 +80,6 @@ int mp_js_process_char(int c) {
|
||||
}
|
||||
|
||||
void mp_js_init(int heap_size) {
|
||||
int stack_dummy;
|
||||
stack_top = (char *)&stack_dummy;
|
||||
|
||||
#if MICROPY_ENABLE_GC
|
||||
char *heap = (char *)malloc(heap_size * sizeof(char));
|
||||
gc_init(heap, heap + heap_size);
|
||||
@ -105,15 +101,14 @@ void mp_js_init_repl() {
|
||||
pyexec_event_repl_init();
|
||||
}
|
||||
|
||||
STATIC void gc_scan_func(void *begin, void *end) {
|
||||
gc_collect_root((void **)begin, (void **)end - (void **)begin + 1);
|
||||
}
|
||||
|
||||
void gc_collect(void) {
|
||||
// WARNING: This gc_collect implementation doesn't try to get root
|
||||
// pointers from CPU registers, and thus may function incorrectly.
|
||||
jmp_buf dummy;
|
||||
if (setjmp(dummy) == 0) {
|
||||
longjmp(dummy, 1);
|
||||
}
|
||||
gc_collect_start();
|
||||
gc_collect_root((void *)stack_top, ((mp_uint_t)(void *)(&dummy + 1) - (mp_uint_t)stack_top) / sizeof(mp_uint_t));
|
||||
emscripten_scan_stack(gc_scan_func);
|
||||
emscripten_scan_registers(gc_scan_func);
|
||||
gc_collect_end();
|
||||
}
|
||||
|
||||
|
||||
@ -116,10 +116,15 @@ SRC_HAL_IMX_C += \
|
||||
$(MCU_DIR)/xip/fsl_flexspi_nor_boot.c \
|
||||
$(MCU_DIR)/project_template/clock_config.c \
|
||||
$(MCU_DIR)/drivers/fsl_adc.c \
|
||||
$(MCU_DIR)/drivers/fsl_cache.c \
|
||||
$(MCU_DIR)/drivers/fsl_clock.c \
|
||||
$(MCU_DIR)/drivers/fsl_dmamux.c \
|
||||
$(MCU_DIR)/drivers/fsl_edma.c \
|
||||
$(MCU_DIR)/drivers/fsl_gpio.c \
|
||||
$(MCU_DIR)/drivers/fsl_gpt.c \
|
||||
$(MCU_DIR)/drivers/fsl_common.c \
|
||||
$(MCU_DIR)/drivers/fsl_lpspi.c \
|
||||
$(MCU_DIR)/drivers/fsl_lpspi_edma.c \
|
||||
$(MCU_DIR)/drivers/fsl_lpuart.c \
|
||||
$(MCU_DIR)/drivers/fsl_flexram.c \
|
||||
$(MCU_DIR)/drivers/fsl_flexspi.c \
|
||||
@ -134,12 +139,15 @@ SRC_C = \
|
||||
ticks.c \
|
||||
tusb_port.c \
|
||||
board_init.c \
|
||||
dma_channel.c \
|
||||
$(BOARD_DIR)/flash_config.c \
|
||||
machine_adc.c \
|
||||
machine_led.c \
|
||||
machine_pin.c \
|
||||
machine_rtc.c \
|
||||
machine_spi.c \
|
||||
machine_timer.c \
|
||||
machine_uart.c \
|
||||
mimxrt_flash.c \
|
||||
modutime.c \
|
||||
modmachine.c \
|
||||
@ -149,7 +157,9 @@ SRC_C = \
|
||||
hal/flexspi_nor_flash.c \
|
||||
lib/mp-readline/readline.c \
|
||||
lib/libc/string0.c \
|
||||
lib/timeutils/timeutils.c \
|
||||
lib/utils/gchelper_native.c \
|
||||
lib/utils/mpirq.c \
|
||||
lib/utils/printf.c \
|
||||
lib/utils/pyexec.c \
|
||||
lib/utils/stdout_helpers.c \
|
||||
@ -262,13 +272,16 @@ SRC_QSTR += \
|
||||
machine_led.c \
|
||||
machine_pin.c \
|
||||
machine_rtc.c \
|
||||
machine_spi.c \
|
||||
machine_timer.c \
|
||||
machine_uart.c \
|
||||
mimxrt_flash.c \
|
||||
modutime.c \
|
||||
modmachine.c \
|
||||
modmimxrt.c \
|
||||
moduos.c \
|
||||
pin.c \
|
||||
lib/utils/mpirq.c \
|
||||
lib/utils/sys_stdio_mphal.c \
|
||||
extmod/modonewire.c \
|
||||
$(GEN_PINS_SRC) \
|
||||
|
||||
@ -8,3 +8,28 @@
|
||||
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
|
||||
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
|
||||
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1010_flexspi_nor_config.h"
|
||||
|
||||
#define MICROPY_HW_NUM_PIN_IRQS (2 * 32)
|
||||
|
||||
// Define mapping logical UART # to hardware UART #
|
||||
// LPUART1 on D0/D1 -> 1
|
||||
// LPUART3 on A0/D4 -> 3
|
||||
// LPUART4 on D6/D7 -> 2
|
||||
|
||||
#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
|
||||
#define MICROPY_HW_UART_INDEX { 0, 1, 4, 3 }
|
||||
|
||||
#define IOMUX_TABLE_UART \
|
||||
{ IOMUXC_GPIO_10_LPUART1_TXD }, { IOMUXC_GPIO_09_LPUART1_RXD }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_08_LPUART3_TXD }, { IOMUXC_GPIO_AD_07_LPUART3_RXD }, \
|
||||
{ IOMUXC_GPIO_AD_02_LPUART4_TXD }, { IOMUXC_GPIO_AD_01_LPUART4_RXD },
|
||||
|
||||
#define MICROPY_HW_SPI_INDEX { 1 }
|
||||
|
||||
#define IOMUX_TABLE_SPI \
|
||||
{ IOMUXC_GPIO_AD_06_LPSPI1_SCK }, { IOMUXC_GPIO_AD_05_LPSPI1_PCS0 }, \
|
||||
{ IOMUXC_GPIO_AD_04_LPSPI1_SDO }, { IOMUXC_GPIO_AD_03_LPSPI1_SDI },
|
||||
|
||||
#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx }
|
||||
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx }
|
||||
|
||||
@ -34,24 +34,3 @@ PWM_CB,GPIO_05
|
||||
ENC_A,GPIO_AD_05
|
||||
ENC_B,GPIO_AD_06
|
||||
LED_GREEN,GPIO_11
|
||||
GPIO_01,GPIO_01
|
||||
GPIO_02,GPIO_02
|
||||
GPIO_03,GPIO_03
|
||||
GPIO_04,GPIO_04
|
||||
GPIO_05,GPIO_05
|
||||
GPIO_06,GPIO_06
|
||||
GPIO_08,GPIO_08
|
||||
GPIO_09,GPIO_09
|
||||
GPIO_10,GPIO_10
|
||||
GPIO_11,GPIO_11
|
||||
GPIO_AD_01,GPIO_AD_01
|
||||
GPIO_AD_02,GPIO_AD_02
|
||||
GPIO_AD_03,GPIO_AD_03
|
||||
GPIO_AD_04,GPIO_AD_04
|
||||
GPIO_AD_05,GPIO_AD_05
|
||||
GPIO_AD_06,GPIO_AD_06
|
||||
GPIO_AD_07,GPIO_AD_07
|
||||
GPIO_AD_09,GPIO_AD_09
|
||||
GPIO_AD_10,GPIO_AD_10
|
||||
GPIO_AD_14,GPIO_AD_14
|
||||
GPIO_SD_02,GPIO_SD_02
|
||||
|
||||
|
@ -9,3 +9,42 @@
|
||||
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
|
||||
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
|
||||
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1020_flexspi_nor_config.h"
|
||||
|
||||
#define MICROPY_HW_NUM_PIN_IRQS (3 * 32)
|
||||
|
||||
// Define mapping logical UART # to hardware UART #
|
||||
// D3/D5 LPUART1 Not usable, Since D3 is blocked.
|
||||
// D0/D1 LPUART2 -> 1
|
||||
// D6/D9 LPUART3 -> 2
|
||||
// D10/D12 LPUART5 -> 3
|
||||
// D14/D15 LPUART8 -> 4
|
||||
// A0/A1 LPUART4 -> 5
|
||||
|
||||
#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
|
||||
#define MICROPY_HW_UART_INDEX { 0, 2, 3, 5, 8, 4 }
|
||||
|
||||
#define IOMUX_TABLE_UART \
|
||||
{ IOMUXC_GPIO_AD_B0_06_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_07_LPUART1_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_08_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_09_LPUART2_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B0_14_LPUART3_TX }, { IOMUXC_GPIO_AD_B0_15_LPUART3_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_10_LPUART4_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART4_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B0_10_LPUART5_TX }, { IOMUXC_GPIO_AD_B0_11_LPUART5_RX }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_SD_B1_02_LPUART8_TX }, { IOMUXC_GPIO_SD_B1_03_LPUART8_RX },
|
||||
|
||||
#define MICROPY_HW_SPI_INDEX { 1, 3 }
|
||||
|
||||
#define IOMUX_TABLE_SPI \
|
||||
{ IOMUXC_GPIO_AD_B0_10_LPSPI1_SCK }, { IOMUXC_GPIO_AD_B0_11_LPSPI1_PCS0 }, \
|
||||
{ IOMUXC_GPIO_AD_B0_12_LPSPI1_SDO }, { IOMUXC_GPIO_AD_B0_13_LPSPI1_SDI }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_12_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B1_13_LPSPI3_PCS0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_15_LPSPI3_SDI },
|
||||
|
||||
#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
|
||||
kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
|
||||
|
||||
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
|
||||
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
|
||||
|
||||
@ -8,3 +8,36 @@
|
||||
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
|
||||
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
|
||||
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1050_flexspi_nor_config.h"
|
||||
|
||||
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
|
||||
|
||||
// Define mapping logical UART # to hardware UART #
|
||||
// LPUART3 on D0/D1 -> 1
|
||||
// LPUART2 on D7/D6 -> 2
|
||||
// LPUART6 on D8/D9 -> 3
|
||||
// LPUART8 on A1/A0 -> 4
|
||||
|
||||
#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
|
||||
#define MICROPY_HW_UART_INDEX { 0, 3, 2, 6, 8 }
|
||||
|
||||
#define IOMUX_TABLE_UART \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
|
||||
|
||||
#define MICROPY_HW_SPI_INDEX { 1 }
|
||||
|
||||
#define IOMUX_TABLE_SPI \
|
||||
{ IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
|
||||
{ IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
|
||||
|
||||
#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
|
||||
kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
|
||||
|
||||
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
|
||||
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
|
||||
|
||||
@ -29,23 +29,3 @@ SDI,GPIO_SD_B0_03
|
||||
SDO,GPIO_SD_B0_02
|
||||
CS,GPIO_SD_B0_01
|
||||
LED_GREEN,GPIO_AD_B0_09
|
||||
GPIO_AD_B1_07,GPIO_AD_B1_07
|
||||
GPIO_AD_B1_06,GPIO_AD_B1_06
|
||||
GPIO_AD_B0_11,GPIO_AD_B0_11
|
||||
GPIO_AD_B1_08,GPIO_AD_B1_08
|
||||
GPIO_AD_B0_09,GPIO_AD_B0_09
|
||||
GPIO_AD_B0_10,GPIO_AD_B0_10
|
||||
GPIO_AD_B1_02,GPIO_AD_B1_02
|
||||
GPIO_AD_B1_03,GPIO_AD_B1_03
|
||||
GPIO_AD_B0_03,GPIO_AD_B0_03
|
||||
GPIO_AD_B0_02,GPIO_AD_B0_02
|
||||
GPIO_SD_B0_01,GPIO_SD_B0_01
|
||||
GPIO_SD_B0_02,GPIO_SD_B0_02
|
||||
GPIO_SD_B0_03,GPIO_SD_B0_03
|
||||
GPIO_SD_B0_00,GPIO_SD_B0_00
|
||||
GPIO_AD_B1_01,GPIO_AD_B1_01
|
||||
GPIO_AD_B1_00,GPIO_AD_B1_00
|
||||
GPIO_AD_B1_10,GPIO_AD_B1_10
|
||||
GPIO_AD_B1_11,GPIO_AD_B1_11
|
||||
GPIO_AD_B1_04,GPIO_AD_B1_04
|
||||
GPIO_AD_B1_05,GPIO_AD_B1_05
|
||||
|
||||
|
@ -8,3 +8,36 @@
|
||||
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
|
||||
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
|
||||
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1060_flexspi_nor_config.h"
|
||||
|
||||
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
|
||||
|
||||
// Define mapping logical UART # to hardware UART #
|
||||
// LPUART3 on D0/D1 -> 1
|
||||
// LPUART2 on D7/D6 -> 2
|
||||
// LPUART6 on D8/D9 -> 3
|
||||
// LPUART8 on A1/A0 -> 4
|
||||
|
||||
#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
|
||||
#define MICROPY_HW_UART_INDEX { 0, 3, 2, 6, 8 }
|
||||
|
||||
#define IOMUX_TABLE_UART \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
|
||||
|
||||
#define MICROPY_HW_SPI_INDEX { 1 }
|
||||
|
||||
#define IOMUX_TABLE_SPI \
|
||||
{ IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
|
||||
{ IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
|
||||
|
||||
#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
|
||||
kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
|
||||
|
||||
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
|
||||
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
|
||||
|
||||
@ -29,23 +29,3 @@ SDI,GPIO_SD_B0_03
|
||||
SDO,GPIO_SD_B0_02
|
||||
CS,GPIO_SD_B0_01
|
||||
LED_GREEN,GPIO_AD_B0_09
|
||||
GPIO_AD_B1_07,GPIO_AD_B1_07
|
||||
GPIO_AD_B1_06,GPIO_AD_B1_06
|
||||
GPIO_AD_B0_11,GPIO_AD_B0_11
|
||||
GPIO_AD_B1_08,GPIO_AD_B1_08
|
||||
GPIO_AD_B0_09,GPIO_AD_B0_09
|
||||
GPIO_AD_B0_10,GPIO_AD_B0_10
|
||||
GPIO_AD_B1_02,GPIO_AD_B1_02
|
||||
GPIO_AD_B1_03,GPIO_AD_B1_03
|
||||
GPIO_AD_B0_03,GPIO_AD_B0_03
|
||||
GPIO_AD_B0_02,GPIO_AD_B0_02
|
||||
GPIO_SD_B0_01,GPIO_SD_B0_01
|
||||
GPIO_SD_B0_02,GPIO_SD_B0_02
|
||||
GPIO_SD_B0_03,GPIO_SD_B0_03
|
||||
GPIO_SD_B0_00,GPIO_SD_B0_00
|
||||
GPIO_AD_B1_01,GPIO_AD_B1_01
|
||||
GPIO_AD_B1_00,GPIO_AD_B1_00
|
||||
GPIO_AD_B1_10,GPIO_AD_B1_10
|
||||
GPIO_AD_B1_11,GPIO_AD_B1_11
|
||||
GPIO_AD_B1_04,GPIO_AD_B1_04
|
||||
GPIO_AD_B1_05,GPIO_AD_B1_05
|
||||
|
||||
|
@ -8,8 +8,8 @@ ivt_size = 0x00001000;
|
||||
interrupts_start = 0x60002000;
|
||||
interrupts_size = 0x00000400;
|
||||
text_start = 0x60002400;
|
||||
text_size = ((((text_start) + 1M) + (4k - 1)) & ~(4k - 1)) - (text_start); /* reserve 1M for code but align on 4k boundary */
|
||||
vfs_start = (text_start) + (text_size);
|
||||
vfs_start = 0x60100000;
|
||||
text_size = ((vfs_start) - (text_start));
|
||||
vfs_size = ((flash_end) - (vfs_start));
|
||||
itcm_start = 0x00000000;
|
||||
itcm_size = 0x00020000;
|
||||
|
||||
@ -1,9 +1,41 @@
|
||||
#define MICROPY_HW_BOARD_NAME "i.MX RT1064 EVK"
|
||||
#define MICROPY_HW_MCU_NAME "MIMXRT1064DVL6A"
|
||||
|
||||
|
||||
// MIMXRT1064_EVK has 1 user LED
|
||||
#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
|
||||
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
|
||||
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin))
|
||||
#define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1064_flexspi_nor_config.h"
|
||||
|
||||
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
|
||||
|
||||
// Define mapping logical UART # to hardware UART #
|
||||
// LPUART3 on D0/D1 -> 1
|
||||
// LPUART2 on D7/D6 -> 2
|
||||
// LPUART6 on D8/D9 -> 3
|
||||
// LPUART8 on A1/A0 -> 4
|
||||
|
||||
#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
|
||||
#define MICROPY_HW_UART_INDEX { 0, 3, 2, 6, 8 }
|
||||
|
||||
#define IOMUX_TABLE_UART \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
|
||||
|
||||
#define MICROPY_HW_SPI_INDEX { 1 }
|
||||
|
||||
#define IOMUX_TABLE_SPI \
|
||||
{ IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
|
||||
{ IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
|
||||
|
||||
#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
|
||||
kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
|
||||
|
||||
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
|
||||
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
|
||||
|
||||
@ -29,23 +29,3 @@ SDI,GPIO_SD_B0_03
|
||||
SDO,GPIO_SD_B0_02
|
||||
CS,GPIO_SD_B0_01
|
||||
LED_GREEN,GPIO_AD_B0_09
|
||||
GPIO_AD_B1_07,GPIO_AD_B1_07
|
||||
GPIO_AD_B1_06,GPIO_AD_B1_06
|
||||
GPIO_AD_B0_11,GPIO_AD_B0_11
|
||||
GPIO_AD_B1_08,GPIO_AD_B1_08
|
||||
GPIO_AD_B0_09,GPIO_AD_B0_09
|
||||
GPIO_AD_B0_10,GPIO_AD_B0_10
|
||||
GPIO_AD_B1_02,GPIO_AD_B1_02
|
||||
GPIO_AD_B1_03,GPIO_AD_B1_03
|
||||
GPIO_AD_B0_03,GPIO_AD_B0_03
|
||||
GPIO_AD_B0_02,GPIO_AD_B0_02
|
||||
GPIO_SD_B0_01,GPIO_SD_B0_01
|
||||
GPIO_SD_B0_02,GPIO_SD_B0_02
|
||||
GPIO_SD_B0_03,GPIO_SD_B0_03
|
||||
GPIO_SD_B0_00,GPIO_SD_B0_00
|
||||
GPIO_AD_B1_01,GPIO_AD_B1_01
|
||||
GPIO_AD_B1_00,GPIO_AD_B1_00
|
||||
GPIO_AD_B1_10,GPIO_AD_B1_10
|
||||
GPIO_AD_B1_11,GPIO_AD_B1_11
|
||||
GPIO_AD_B1_04,GPIO_AD_B1_04
|
||||
GPIO_AD_B1_05,GPIO_AD_B1_05
|
||||
|
||||
|
@ -8,3 +8,37 @@
|
||||
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
|
||||
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
|
||||
#define BOARD_FLASH_CONFIG_HEADER_H "teensy40_flexspi_nor_config.h"
|
||||
|
||||
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
|
||||
|
||||
// UART config: 7 UARTs at the pins for Teensy 4.0
|
||||
#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
|
||||
#define MICROPY_HW_UART_INDEX { 0, 6, 4, 2, 3, 8, 1, 7 }
|
||||
|
||||
#define IOMUX_TABLE_UART \
|
||||
{ IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
|
||||
{ IOMUXC_GPIO_B1_00_LPUART4_TX }, { IOMUXC_GPIO_B1_01_LPUART4_RX }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
|
||||
{ IOMUXC_GPIO_EMC_31_LPUART7_TX }, { IOMUXC_GPIO_EMC_32_LPUART7_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
|
||||
|
||||
#define MICROPY_HW_SPI_INDEX { 4, 3}
|
||||
|
||||
#define IOMUX_TABLE_SPI \
|
||||
{ 0 }, { 0 }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_15_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B0_03_LPSPI3_PCS0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B0_02_LPSPI3_SDI }, \
|
||||
{ IOMUXC_GPIO_B0_03_LPSPI4_SCK }, { IOMUXC_GPIO_B0_00_LPSPI4_PCS0 }, \
|
||||
{ IOMUXC_GPIO_B0_02_LPSPI4_SDO }, { IOMUXC_GPIO_B0_01_LPSPI4_SDI },
|
||||
|
||||
#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
|
||||
kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
|
||||
|
||||
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
|
||||
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
|
||||
|
||||
@ -5,5 +5,3 @@ MICROPY_FLOAT_IMPL = double
|
||||
|
||||
deploy: $(BUILD)/firmware.hex
|
||||
teensy_loader_cli --mcu=imxrt1062 -v -w $<
|
||||
sleep 1
|
||||
$(PYTHON) $(TOP)/tools/pyboard.py --device $(PORT) $(BOARD_DIR)/format.py
|
||||
|
||||
34
ports/mimxrt/boards/TEENSY41/mpconfigboard.h
Executable file → Normal file
34
ports/mimxrt/boards/TEENSY41/mpconfigboard.h
Executable file → Normal file
@ -8,3 +8,37 @@
|
||||
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
|
||||
#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
|
||||
#define BOARD_FLASH_CONFIG_HEADER_H "teensy41_flexspi_nor_config.h"
|
||||
|
||||
#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3)
|
||||
|
||||
// UART config: 8 UARTs at the pins for Teensy 4.1
|
||||
#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
|
||||
#define MICROPY_HW_UART_INDEX { 0, 6, 4, 2, 3, 8, 1, 7, 5 }
|
||||
|
||||
#define IOMUX_TABLE_UART \
|
||||
{ IOMUXC_GPIO_AD_B0_12_LPUART1_TX }, { IOMUXC_GPIO_AD_B0_13_LPUART1_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_02_LPUART2_TX }, { IOMUXC_GPIO_AD_B1_03_LPUART2_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_06_LPUART3_TX }, { IOMUXC_GPIO_AD_B1_07_LPUART3_RX }, \
|
||||
{ IOMUXC_GPIO_B1_00_LPUART4_TX }, { IOMUXC_GPIO_B1_01_LPUART4_RX }, \
|
||||
{ IOMUXC_GPIO_B1_12_LPUART5_TX }, { IOMUXC_GPIO_B1_13_LPUART5_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
|
||||
{ IOMUXC_GPIO_EMC_31_LPUART7_TX }, { IOMUXC_GPIO_EMC_32_LPUART7_RX }, \
|
||||
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
|
||||
|
||||
#define MICROPY_HW_SPI_INDEX { 4, 3, 1 }
|
||||
|
||||
#define IOMUX_TABLE_SPI \
|
||||
{ IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
|
||||
{ IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ 0 }, { 0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_15_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B1_12_LPSPI3_PCS0 }, \
|
||||
{ IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_13_LPSPI3_SDI }, \
|
||||
{ IOMUXC_GPIO_B0_03_LPSPI4_SCK }, { IOMUXC_GPIO_B0_00_LPSPI4_PCS0 }, \
|
||||
{ IOMUXC_GPIO_B0_02_LPSPI4_SDO }, { IOMUXC_GPIO_B0_01_LPSPI4_SDI },
|
||||
|
||||
#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
|
||||
kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
|
||||
|
||||
#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
|
||||
kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
|
||||
|
||||
51
ports/mimxrt/dma_channel.c
Normal file
51
ports/mimxrt/dma_channel.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Robert Hammelrath
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "dma_channel.h"
|
||||
|
||||
// List of channel flags: true: channel used, false: channel available
|
||||
static bool channel_list[32] = { true, true, true, true, false, false, false, false,
|
||||
false, false, false, false, false, false, false, false,
|
||||
false, false, false, false, false, false, false, false,
|
||||
false, false, false, false, false, false, false, false };
|
||||
|
||||
// allocate_channel(): retrieve an available channel. Return the number or -1
|
||||
int allocate_dma_channel(void) {
|
||||
for (int i = 0; i < ARRAY_SIZE(channel_list); i++) {
|
||||
if (channel_list[i] == false) { // Channel available
|
||||
channel_list[i] = true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// free_channel(n): Declare channel as free
|
||||
void free_dma_channel(int n) {
|
||||
if (n >= 0 && n <= ARRAY_SIZE(channel_list)) {
|
||||
channel_list[n] = false;
|
||||
}
|
||||
}
|
||||
34
ports/mimxrt/dma_channel.h
Normal file
34
ports/mimxrt/dma_channel.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Robert Hammelrath
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_MIMXRT_DMACHANNEL_H
|
||||
#define MICROPY_INCLUDED_MIMXRT_DMACHANNEL_H
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
int allocate_dma_channel(void);
|
||||
void free_dma_channel(int n);
|
||||
|
||||
#endif // MICROPY_INCLUDED_MIMXRT_DMACHANNEL_H
|
||||
@ -4,6 +4,7 @@
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Philipp Ebensberger
|
||||
* Copyright (c) 2021 Robert Hammelrath
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -30,8 +31,8 @@
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "lib/utils/mpirq.h"
|
||||
#include "pin.h"
|
||||
#include "mphalport.h"
|
||||
|
||||
// Local functions
|
||||
STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
@ -68,6 +69,95 @@ const mp_obj_type_t machine_pin_board_pins_obj_type = {
|
||||
.locals_dict = (mp_obj_t)&machine_pin_board_pins_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_irq_methods_t machine_pin_irq_methods;
|
||||
|
||||
static GPIO_Type *gpiobases[] = GPIO_BASE_PTRS;
|
||||
STATIC const uint16_t GPIO_combined_low_irqs[] = GPIO_COMBINED_LOW_IRQS;
|
||||
STATIC const uint16_t GPIO_combined_high_irqs[] = GPIO_COMBINED_HIGH_IRQS;
|
||||
STATIC const uint16_t IRQ_mapping[] = {kGPIO_NoIntmode, kGPIO_IntRisingEdge, kGPIO_IntFallingEdge, kGPIO_IntRisingOrFallingEdge};
|
||||
#define GET_PIN_IRQ_INDEX(gpio_nr, pin) ((gpio_nr - 1) * 32 + pin)
|
||||
|
||||
int GPIO_get_instance(GPIO_Type *gpio) {
|
||||
int gpio_nr;
|
||||
for (gpio_nr = 0; gpio_nr < ARRAY_SIZE(gpiobases); gpio_nr++) {
|
||||
if (gpio == gpiobases[gpio_nr]) {
|
||||
return gpio_nr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void call_handler(GPIO_Type *gpio, int gpio_nr, int pin) {
|
||||
uint32_t mask = 1 << pin;
|
||||
uint32_t isr = gpio->ISR & gpio->IMR;
|
||||
for (int i = 0; i < 16; i++, pin++, mask <<= 1) {
|
||||
// Did the ISR fire? Consider only the bits that are enabled.
|
||||
if (isr & mask) {
|
||||
gpio->ISR = mask; // clear the ISR flag
|
||||
int index = GET_PIN_IRQ_INDEX(gpio_nr, pin);
|
||||
machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[index]);
|
||||
if (irq != NULL) {
|
||||
irq->flags = irq->trigger;
|
||||
mp_irq_handler(&irq->base);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 10 GPIO IRQ handlers, each covering 16 bits.
|
||||
|
||||
void GPIO1_Combined_0_15_IRQHandler(void) {
|
||||
call_handler(gpiobases[1], 1, 0);
|
||||
}
|
||||
|
||||
void GPIO1_Combined_16_31_IRQHandler(void) {
|
||||
call_handler(gpiobases[1], 1, 16);
|
||||
}
|
||||
|
||||
void GPIO2_Combined_0_15_IRQHandler(void) {
|
||||
call_handler(gpiobases[2], 2, 0);
|
||||
}
|
||||
|
||||
void GPIO2_Combined_16_31_IRQHandler(void) {
|
||||
call_handler(gpiobases[2], 2, 16);
|
||||
}
|
||||
|
||||
void GPIO3_Combined_0_15_IRQHandler(void) {
|
||||
call_handler(gpiobases[3], 3, 0);
|
||||
}
|
||||
|
||||
void GPIO3_Combined_16_31_IRQHandler(void) {
|
||||
call_handler(gpiobases[3], 3, 16);
|
||||
}
|
||||
|
||||
void GPIO4_Combined_0_15_IRQHandler(void) {
|
||||
call_handler(gpiobases[4], 4, 0);
|
||||
}
|
||||
|
||||
void GPIO4_Combined_16_31_IRQHandler(void) {
|
||||
call_handler(gpiobases[4], 4, 16);
|
||||
}
|
||||
|
||||
void GPIO5_Combined_0_15_IRQHandler(void) {
|
||||
call_handler(gpiobases[5], 5, 0);
|
||||
}
|
||||
|
||||
void GPIO5_Combined_16_31_IRQHandler(void) {
|
||||
call_handler(gpiobases[5], 5, 16);
|
||||
}
|
||||
|
||||
// Deinit all pin IRQ handlers.
|
||||
void machine_pin_irq_deinit(void) {
|
||||
for (int i = 0; i < ARRAY_SIZE(MP_STATE_PORT(machine_pin_irq_objects)); ++i) {
|
||||
machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[i]);
|
||||
if (irq != NULL) {
|
||||
machine_pin_obj_t *self = MP_OBJ_TO_PTR(irq->base.parent);
|
||||
GPIO_PortDisableInterrupts(self->gpio, 1U << self->pin);
|
||||
MP_STATE_PORT(machine_pin_irq_objects[i]) = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simplified mode setting used by the extmod modules
|
||||
void machine_pin_set_mode(const machine_pin_obj_t *self, uint8_t mode) {
|
||||
gpio_pin_config_t pin_config = {kGPIO_DigitalInput, 1, kGPIO_NoIntmode};
|
||||
@ -234,6 +324,69 @@ STATIC mp_obj_t machine_pin_init(size_t n_args, const mp_obj_t *args, mp_map_t *
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_init);
|
||||
|
||||
// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
|
||||
STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_handler, ARG_trigger, ARG_hard };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = 3} },
|
||||
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// Get the IRQ object.
|
||||
uint32_t gpio_nr = GPIO_get_instance(self->gpio);
|
||||
uint32_t index = GET_PIN_IRQ_INDEX(gpio_nr, self->pin);
|
||||
if (index >= ARRAY_SIZE(MP_STATE_PORT(machine_pin_irq_objects))) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("IRQ not supported on given Pin"));
|
||||
}
|
||||
machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[index]);
|
||||
|
||||
// Allocate the IRQ object if it doesn't already exist.
|
||||
if (irq == NULL) {
|
||||
irq = m_new_obj(machine_pin_irq_obj_t);
|
||||
irq->base.base.type = &mp_irq_type;
|
||||
irq->base.methods = (mp_irq_methods_t *)&machine_pin_irq_methods;
|
||||
irq->base.parent = MP_OBJ_FROM_PTR(self);
|
||||
irq->base.handler = mp_const_none;
|
||||
irq->base.ishard = false;
|
||||
MP_STATE_PORT(machine_pin_irq_objects[index]) = irq;
|
||||
}
|
||||
|
||||
if (n_args > 1 || kw_args->used != 0) {
|
||||
// Configure IRQ.
|
||||
uint32_t irq_num = self->pin < 16 ? GPIO_combined_low_irqs[gpio_nr] : GPIO_combined_high_irqs[gpio_nr];
|
||||
|
||||
// Disable all IRQs from the affected source while data is updated.
|
||||
DisableIRQ(irq_num);
|
||||
GPIO_PortDisableInterrupts(self->gpio, 1U << self->pin);
|
||||
|
||||
// Update IRQ data.
|
||||
irq->base.handler = args[ARG_handler].u_obj;
|
||||
irq->base.ishard = args[ARG_hard].u_bool;
|
||||
irq->flags = 0;
|
||||
if (args[ARG_trigger].u_int >= ARRAY_SIZE(IRQ_mapping)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("IRQ mode not supported"));
|
||||
}
|
||||
irq->trigger = IRQ_mapping[args[ARG_trigger].u_int];
|
||||
|
||||
// Enable IRQ if a handler is given.
|
||||
if (args[ARG_handler].u_obj != mp_const_none) {
|
||||
// Set the pin mode
|
||||
GPIO_PinSetInterruptConfig(self->gpio, self->pin, irq->trigger);
|
||||
// Enable the specific Pin interrupt
|
||||
GPIO_PortEnableInterrupts(self->gpio, 1U << self->pin);
|
||||
}
|
||||
// Enable LEVEL1 interrupt again
|
||||
EnableIRQ(irq_num);
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(irq);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_off_obj) },
|
||||
@ -242,6 +395,7 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&machine_pin_on_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) },
|
||||
// class attributes
|
||||
{ MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&machine_pin_board_pins_obj_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_cpu), MP_ROM_PTR(&machine_pin_cpu_pins_obj_type) },
|
||||
@ -265,6 +419,9 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_POWER_5), MP_ROM_INT(PIN_DRIVE_POWER_5) }, // R0/6
|
||||
{ MP_ROM_QSTR(MP_QSTR_POWER_6), MP_ROM_INT(PIN_DRIVE_POWER_6) }, // R0/7
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(1) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(2) },
|
||||
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
|
||||
|
||||
@ -285,3 +442,37 @@ const mp_obj_type_t machine_pin_af_type = {
|
||||
.make_new = mp_pin_make_new,
|
||||
.locals_dict = (mp_obj_dict_t *)&machine_pin_locals_dict,
|
||||
};
|
||||
|
||||
STATIC mp_uint_t machine_pin_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
|
||||
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uint32_t gpio_nr = GPIO_get_instance(self->gpio);
|
||||
machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[GET_PIN_IRQ_INDEX(gpio_nr, self->pin)]);
|
||||
uint32_t irq_num = self->pin < 16 ? GPIO_combined_low_irqs[gpio_nr] : GPIO_combined_high_irqs[gpio_nr];
|
||||
DisableIRQ(irq_num);
|
||||
irq->flags = 0;
|
||||
irq->trigger = new_trigger;
|
||||
// Configure the interrupt.
|
||||
GPIO_PinSetInterruptConfig(self->gpio, self->pin, irq->trigger);
|
||||
// Enable LEVEL1 interrupt.
|
||||
EnableIRQ(irq_num);
|
||||
// Enable the specific pin interrupt.
|
||||
GPIO_PortEnableInterrupts(self->gpio, 1U << self->pin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t machine_pin_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
|
||||
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uint32_t gpio_nr = GPIO_get_instance(self->gpio);
|
||||
machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[GET_PIN_IRQ_INDEX(gpio_nr, self->pin)]);
|
||||
if (info_type == MP_IRQ_INFO_FLAGS) {
|
||||
return irq->flags;
|
||||
} else if (info_type == MP_IRQ_INFO_TRIGGERS) {
|
||||
return irq->trigger;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC const mp_irq_methods_t machine_pin_irq_methods = {
|
||||
.trigger = machine_pin_irq_trigger,
|
||||
.info = machine_pin_irq_info,
|
||||
};
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "modmachine.h"
|
||||
#include "ticks.h"
|
||||
#include "fsl_snvs_lp.h"
|
||||
@ -37,13 +38,7 @@ typedef struct _machine_rtc_obj_t {
|
||||
|
||||
// Singleton RTC object.
|
||||
STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}};
|
||||
|
||||
// Calculate the weekday from the date.
|
||||
// The result is zero based with 0 = Sunday.
|
||||
// by Michael Keith and Tom Craver, 1990.
|
||||
static int calc_weekday(int y, int m, int d) {
|
||||
return (d += m < 3 ? y-- : y - 2, 23 * m / 9 + d + 4 + y / 4 - y / 100 + y / 400) % 7;
|
||||
}
|
||||
uint32_t us_offset = 0;
|
||||
|
||||
STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// Check arguments.
|
||||
@ -66,11 +61,11 @@ STATIC mp_obj_t machine_rtc_datetime_helper(size_t n_args, const mp_obj_t *args)
|
||||
mp_obj_new_int(srtc_date.year),
|
||||
mp_obj_new_int(srtc_date.month),
|
||||
mp_obj_new_int(srtc_date.day),
|
||||
mp_obj_new_int(timeutils_calc_weekday(srtc_date.year, srtc_date.month, srtc_date.day)),
|
||||
mp_obj_new_int(srtc_date.hour),
|
||||
mp_obj_new_int(srtc_date.minute),
|
||||
mp_obj_new_int(srtc_date.second),
|
||||
mp_obj_new_int(ticks_us64() % 1000000),
|
||||
mp_const_none,
|
||||
mp_obj_new_int((ticks_us64() + us_offset) % 1000000),
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
} else {
|
||||
@ -84,12 +79,14 @@ STATIC mp_obj_t machine_rtc_datetime_helper(size_t n_args, const mp_obj_t *args)
|
||||
srtc_date.year = year >= 100 ? year : year + 2000; // allow 21 for 2021
|
||||
srtc_date.month = mp_obj_get_int(items[1]);
|
||||
srtc_date.day = mp_obj_get_int(items[2]);
|
||||
srtc_date.hour = mp_obj_get_int(items[3]);
|
||||
srtc_date.minute = mp_obj_get_int(items[4]);
|
||||
srtc_date.second = mp_obj_get_int(items[5]);
|
||||
// Ignore weekday at items[3]
|
||||
srtc_date.hour = mp_obj_get_int(items[4]);
|
||||
srtc_date.minute = mp_obj_get_int(items[5]);
|
||||
srtc_date.second = mp_obj_get_int(items[6]);
|
||||
if (SNVS_LP_SRTC_SetDatetime(SNVS, &srtc_date) != kStatus_Success) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
us_offset = (1000000 + mp_obj_get_int(items[7]) - ticks_us64() % 1000000) % 1000000;
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
@ -101,7 +98,21 @@ STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);
|
||||
|
||||
STATIC mp_obj_t machine_rtc_now(mp_obj_t self_in) {
|
||||
return machine_rtc_datetime_helper(1, &self_in);
|
||||
// Get date and time in CPython order.
|
||||
snvs_lp_srtc_datetime_t srtc_date;
|
||||
SNVS_LP_SRTC_GetDatetime(SNVS, &srtc_date);
|
||||
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(srtc_date.year),
|
||||
mp_obj_new_int(srtc_date.month),
|
||||
mp_obj_new_int(srtc_date.day),
|
||||
mp_obj_new_int(srtc_date.hour),
|
||||
mp_obj_new_int(srtc_date.minute),
|
||||
mp_obj_new_int(srtc_date.second),
|
||||
mp_obj_new_int((ticks_us64() + us_offset) % 1000000),
|
||||
mp_const_none,
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_now_obj, machine_rtc_now);
|
||||
|
||||
@ -112,16 +123,6 @@ STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init);
|
||||
|
||||
STATIC mp_obj_t machine_rtc_weekday(mp_obj_t self_in) {
|
||||
(void)self_in; // unused
|
||||
int day;
|
||||
snvs_lp_srtc_datetime_t srtc_date;
|
||||
SNVS_LP_SRTC_GetDatetime(SNVS, &srtc_date);
|
||||
day = calc_weekday(srtc_date.year, srtc_date.month, srtc_date.day);
|
||||
return MP_OBJ_NEW_SMALL_INT((day + 6) % 7);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_rtc_weekday_obj, machine_rtc_weekday);
|
||||
|
||||
// calibration(cal)
|
||||
// When the argument is a number in the range [-16 to 15], set the calibration value.
|
||||
STATIC mp_obj_t machine_rtc_calibration(mp_obj_t self_in, mp_obj_t cal_in) {
|
||||
@ -143,7 +144,6 @@ STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_now), MP_ROM_PTR(&machine_rtc_now_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_weekday), MP_ROM_PTR(&machine_rtc_weekday_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_calibration), MP_ROM_PTR(&machine_rtc_calibration_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table);
|
||||
|
||||
334
ports/mimxrt/machine_spi.c
Normal file
334
ports/mimxrt/machine_spi.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020-2021 Damien P. George
|
||||
* Copyright (c) 2021 Robert Hammelrath
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "extmod/machine_spi.h"
|
||||
#include "modmachine.h"
|
||||
#include "dma_channel.h"
|
||||
|
||||
#include "fsl_cache.h"
|
||||
#include "fsl_dmamux.h"
|
||||
#include "fsl_iomuxc.h"
|
||||
#include "fsl_lpspi.h"
|
||||
#include "fsl_lpspi_edma.h"
|
||||
|
||||
#define DEFAULT_SPI_BAUDRATE (1000000)
|
||||
#define DEFAULT_SPI_POLARITY (0)
|
||||
#define DEFAULT_SPI_PHASE (0)
|
||||
#define DEFAULT_SPI_BITS (8)
|
||||
#define DEFAULT_SPI_FIRSTBIT (kLPSPI_MsbFirst)
|
||||
#define DEFAULT_SPI_DRIVE (6)
|
||||
|
||||
#define CLOCK_DIVIDER (1)
|
||||
|
||||
#define MICROPY_HW_SPI_NUM MP_ARRAY_SIZE(spi_index_table)
|
||||
|
||||
#define SCK (iomux_table[index])
|
||||
#define CS0 (iomux_table[index + 1])
|
||||
#define SDO (iomux_table[index + 2])
|
||||
#define SDI (iomux_table[index + 3])
|
||||
|
||||
typedef struct _machine_spi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint8_t spi_id;
|
||||
uint8_t mode;
|
||||
uint8_t spi_hw_id;
|
||||
bool transfer_busy;
|
||||
LPSPI_Type *spi_inst;
|
||||
lpspi_master_config_t *master_config;
|
||||
} machine_spi_obj_t;
|
||||
|
||||
typedef struct _iomux_table_t {
|
||||
uint32_t muxRegister;
|
||||
uint32_t muxMode;
|
||||
uint32_t inputRegister;
|
||||
uint32_t inputDaisy;
|
||||
uint32_t configRegister;
|
||||
} iomux_table_t;
|
||||
|
||||
STATIC const uint8_t spi_index_table[] = MICROPY_HW_SPI_INDEX;
|
||||
STATIC LPSPI_Type *spi_base_ptr_table[] = LPSPI_BASE_PTRS;
|
||||
static const iomux_table_t iomux_table[] = {
|
||||
IOMUX_TABLE_SPI
|
||||
};
|
||||
|
||||
static uint16_t dma_req_src_rx[] = DMA_REQ_SRC_RX;
|
||||
static uint16_t dma_req_src_tx[] = DMA_REQ_SRC_TX;
|
||||
|
||||
bool lpspi_set_iomux(int8_t spi, uint8_t drive) {
|
||||
int index = (spi - 1) * 4;
|
||||
|
||||
if (SCK.muxRegister != 0) {
|
||||
IOMUXC_SetPinMux(SCK.muxRegister, SCK.muxMode, SCK.inputRegister, SCK.inputDaisy, SCK.configRegister, 0U);
|
||||
IOMUXC_SetPinConfig(SCK.muxRegister, SCK.muxMode, SCK.inputRegister, SCK.inputDaisy, SCK.configRegister,
|
||||
0x1080u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
|
||||
|
||||
IOMUXC_SetPinMux(CS0.muxRegister, CS0.muxMode, CS0.inputRegister, CS0.inputDaisy, CS0.configRegister, 0U);
|
||||
IOMUXC_SetPinConfig(CS0.muxRegister, CS0.muxMode, CS0.inputRegister, CS0.inputDaisy, CS0.configRegister,
|
||||
0x1080u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
|
||||
|
||||
IOMUXC_SetPinMux(SDO.muxRegister, SDO.muxMode, SDO.inputRegister, SDO.inputDaisy, SDO.configRegister, 0U);
|
||||
IOMUXC_SetPinConfig(SDO.muxRegister, SDO.muxMode, SDO.inputRegister, SDO.inputDaisy, SDO.configRegister,
|
||||
0x1080u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
|
||||
|
||||
IOMUXC_SetPinMux(SDI.muxRegister, SDI.muxMode, SDI.inputRegister, SDI.inputDaisy, SDI.configRegister, 0U);
|
||||
IOMUXC_SetPinConfig(SDI.muxRegister, SDI.muxMode, SDI.inputRegister, SDI.inputDaisy, SDI.configRegister,
|
||||
0x1080u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void machine_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
static const char *firstbit_str[] = {"MSB", "LSB"};
|
||||
machine_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "SPI(%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%s, gap_ns=%d)",
|
||||
self->spi_id, self->master_config->baudRate, self->master_config->cpol,
|
||||
self->master_config->cpha, self->master_config->bitsPerFrame,
|
||||
firstbit_str[self->master_config->direction], self->master_config->betweenTransferDelayInNanoSec);
|
||||
}
|
||||
|
||||
mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_gap_ns, ARG_drive };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = DEFAULT_SPI_BAUDRATE} },
|
||||
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_POLARITY} },
|
||||
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_PHASE} },
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_BITS} },
|
||||
{ MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_FIRSTBIT} },
|
||||
{ MP_QSTR_gap_ns, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_DRIVE} },
|
||||
};
|
||||
|
||||
static bool clk_init = true;
|
||||
|
||||
// Parse the arguments.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// Get the SPI bus id.
|
||||
int spi_id = mp_obj_get_int(args[ARG_id].u_obj);
|
||||
if (spi_id < 0 || spi_id >= MP_ARRAY_SIZE(spi_index_table)) {
|
||||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id);
|
||||
}
|
||||
|
||||
// Get peripheral object.
|
||||
uint8_t spi_hw_id = spi_index_table[spi_id]; // the hw spi number 1..n
|
||||
machine_spi_obj_t *self = m_new_obj(machine_spi_obj_t);
|
||||
self->base.type = &machine_spi_type;
|
||||
self->spi_id = spi_id;
|
||||
self->spi_inst = spi_base_ptr_table[spi_hw_id];
|
||||
self->spi_hw_id = spi_hw_id;
|
||||
|
||||
uint8_t drive = args[ARG_drive].u_int;
|
||||
if (drive < 1 || drive > 7) {
|
||||
drive = DEFAULT_SPI_DRIVE;
|
||||
}
|
||||
|
||||
if (clk_init) {
|
||||
clk_init = false;
|
||||
/*Set clock source for LPSPI*/
|
||||
CLOCK_SetMux(kCLOCK_LpspiMux, 1); // Clock source is kCLOCK_Usb1PllPfd1Clk
|
||||
CLOCK_SetDiv(kCLOCK_LpspiDiv, CLOCK_DIVIDER);
|
||||
}
|
||||
lpspi_set_iomux(spi_index_table[spi_id], drive);
|
||||
LPSPI_Reset(self->spi_inst);
|
||||
LPSPI_Enable(self->spi_inst, false); // Disable first before new settings are applies
|
||||
|
||||
self->master_config = m_new_obj(lpspi_master_config_t);
|
||||
LPSPI_MasterGetDefaultConfig(self->master_config);
|
||||
// Initialise the SPI peripheral.
|
||||
self->master_config->baudRate = args[ARG_baudrate].u_int;
|
||||
self->master_config->betweenTransferDelayInNanoSec = 1000000000 / self->master_config->baudRate * 2;
|
||||
self->master_config->cpol = args[ARG_polarity].u_int;
|
||||
self->master_config->cpha = args[ARG_phase].u_int;
|
||||
self->master_config->bitsPerFrame = args[ARG_bits].u_int;
|
||||
self->master_config->direction = args[ARG_firstbit].u_int;
|
||||
if (args[ARG_gap_ns].u_int != -1) {
|
||||
self->master_config->betweenTransferDelayInNanoSec = args[ARG_gap_ns].u_int;
|
||||
}
|
||||
LPSPI_MasterInit(self->spi_inst, self->master_config, CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (CLOCK_DIVIDER + 1));
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC void machine_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_gap_ns };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_gap_ns, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
|
||||
// Parse the arguments.
|
||||
machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// Reconfigure the baudrate if requested.
|
||||
if (args[ARG_baudrate].u_int != -1) {
|
||||
self->master_config->baudRate = args[ARG_baudrate].u_int;
|
||||
self->master_config->betweenTransferDelayInNanoSec = 1000000000 / self->master_config->baudRate * 2;
|
||||
}
|
||||
// Reconfigure the format if requested.
|
||||
if (args[ARG_polarity].u_int != -1) {
|
||||
self->master_config->cpol = args[ARG_polarity].u_int;
|
||||
}
|
||||
if (args[ARG_phase].u_int != -1) {
|
||||
self->master_config->cpha = args[ARG_phase].u_int;
|
||||
}
|
||||
if (args[ARG_bits].u_int != -1) {
|
||||
self->master_config->bitsPerFrame = args[ARG_bits].u_int;
|
||||
}
|
||||
if (args[ARG_firstbit].u_int != -1) {
|
||||
self->master_config->direction = args[ARG_firstbit].u_int;
|
||||
}
|
||||
if (args[ARG_gap_ns].u_int != -1) {
|
||||
self->master_config->betweenTransferDelayInNanoSec = args[ARG_gap_ns].u_int;
|
||||
}
|
||||
LPSPI_Enable(self->spi_inst, false); // Disable first before new settings are applies
|
||||
LPSPI_MasterInit(self->spi_inst, self->master_config, CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (CLOCK_DIVIDER + 1));
|
||||
}
|
||||
|
||||
void LPSPI_EDMAMasterCallback(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, status_t status, void *self_in) {
|
||||
machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
|
||||
self->transfer_busy = false;
|
||||
}
|
||||
|
||||
STATIC void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||
machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
|
||||
// Use DMA for large transfers if channels are available
|
||||
const size_t dma_min_size_threshold = 16; // That's the FIFO size
|
||||
|
||||
int chan_tx = -1;
|
||||
int chan_rx = -1;
|
||||
if (len >= dma_min_size_threshold) {
|
||||
// Use two DMA channels to service the two FIFOs
|
||||
chan_rx = allocate_dma_channel();
|
||||
chan_tx = allocate_dma_channel();
|
||||
}
|
||||
bool use_dma = chan_rx >= 0 && chan_tx >= 0;
|
||||
|
||||
if (use_dma) {
|
||||
edma_config_t userConfig;
|
||||
|
||||
/* DMA MUX init*/
|
||||
DMAMUX_Init(DMAMUX);
|
||||
|
||||
DMAMUX_SetSource(DMAMUX, chan_rx, dma_req_src_rx[self->spi_hw_id]); // ## SPIn source
|
||||
DMAMUX_EnableChannel(DMAMUX, chan_rx);
|
||||
|
||||
DMAMUX_SetSource(DMAMUX, chan_tx, dma_req_src_tx[self->spi_hw_id]);
|
||||
DMAMUX_EnableChannel(DMAMUX, chan_tx);
|
||||
|
||||
EDMA_GetDefaultConfig(&userConfig);
|
||||
EDMA_Init(DMA0, &userConfig);
|
||||
|
||||
lpspi_master_edma_handle_t g_master_edma_handle;
|
||||
edma_handle_t lpspiEdmaMasterRxRegToRxDataHandle;
|
||||
edma_handle_t lpspiEdmaMasterTxDataToTxRegHandle;
|
||||
|
||||
// Set up lpspi EDMA master
|
||||
EDMA_CreateHandle(&(lpspiEdmaMasterRxRegToRxDataHandle), DMA0, chan_rx);
|
||||
EDMA_CreateHandle(&(lpspiEdmaMasterTxDataToTxRegHandle), DMA0, chan_tx);
|
||||
LPSPI_MasterTransferCreateHandleEDMA(self->spi_inst, &g_master_edma_handle, LPSPI_EDMAMasterCallback, self,
|
||||
&lpspiEdmaMasterRxRegToRxDataHandle,
|
||||
&lpspiEdmaMasterTxDataToTxRegHandle);
|
||||
// Start master transfer
|
||||
lpspi_transfer_t masterXfer;
|
||||
masterXfer.txData = (uint8_t *)src;
|
||||
masterXfer.rxData = (uint8_t *)dest;
|
||||
masterXfer.dataSize = len;
|
||||
masterXfer.configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
|
||||
|
||||
// Reconfigure the TCR, required after switch between DMA vs. non-DMA
|
||||
LPSPI_Enable(self->spi_inst, false); // Disable first before new settings are applied
|
||||
self->spi_inst->TCR = LPSPI_TCR_CPOL(self->master_config->cpol) | LPSPI_TCR_CPHA(self->master_config->cpha) |
|
||||
LPSPI_TCR_LSBF(self->master_config->direction) | LPSPI_TCR_FRAMESZ(self->master_config->bitsPerFrame - 1) |
|
||||
(self->spi_inst->TCR & LPSPI_TCR_PRESCALE_MASK) | LPSPI_TCR_PCS(self->master_config->whichPcs);
|
||||
LPSPI_Enable(self->spi_inst, true);
|
||||
|
||||
self->transfer_busy = true;
|
||||
if (dest) {
|
||||
L1CACHE_DisableDCache();
|
||||
} else if (src) {
|
||||
DCACHE_CleanByRange((uint32_t)src, len);
|
||||
}
|
||||
LPSPI_MasterTransferEDMA(self->spi_inst, &g_master_edma_handle, &masterXfer);
|
||||
|
||||
while (self->transfer_busy) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
}
|
||||
L1CACHE_EnableDCache();
|
||||
}
|
||||
// Release DMA channels, even if never allocated.
|
||||
if (chan_rx >= 0) {
|
||||
free_dma_channel(chan_rx);
|
||||
}
|
||||
if (chan_tx >= 0) {
|
||||
free_dma_channel(chan_tx);
|
||||
}
|
||||
|
||||
if (!use_dma) {
|
||||
// Reconfigure the TCR, required after switch between DMA vs. non-DMA
|
||||
LPSPI_Enable(self->spi_inst, false); // Disable first before new settings are applied
|
||||
self->spi_inst->TCR = LPSPI_TCR_CPOL(self->master_config->cpol) | LPSPI_TCR_CPHA(self->master_config->cpha) |
|
||||
LPSPI_TCR_LSBF(self->master_config->direction) | LPSPI_TCR_FRAMESZ(self->master_config->bitsPerFrame - 1) |
|
||||
(self->spi_inst->TCR & LPSPI_TCR_PRESCALE_MASK) | LPSPI_TCR_PCS(self->master_config->whichPcs);
|
||||
LPSPI_Enable(self->spi_inst, true);
|
||||
|
||||
lpspi_transfer_t masterXfer;
|
||||
masterXfer.txData = (uint8_t *)src;
|
||||
masterXfer.rxData = (uint8_t *)dest;
|
||||
masterXfer.dataSize = len;
|
||||
masterXfer.configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
|
||||
|
||||
LPSPI_MasterTransferBlocking(self->spi_inst, &masterXfer);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_machine_spi_p_t machine_spi_p = {
|
||||
.init = machine_spi_init,
|
||||
.transfer = machine_spi_transfer,
|
||||
};
|
||||
|
||||
const mp_obj_type_t machine_spi_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_SPI,
|
||||
.print = machine_spi_print,
|
||||
.make_new = machine_spi_make_new,
|
||||
.protocol = &machine_spi_p,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
|
||||
};
|
||||
465
ports/mimxrt/machine_uart.c
Normal file
465
ports/mimxrt/machine_uart.c
Normal file
@ -0,0 +1,465 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020-2021 Damien P. George
|
||||
* Copyright (c) 2021 Robert Hammelrath
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mphal.h"
|
||||
#include "ticks.h"
|
||||
#include "fsl_common.h"
|
||||
#include "fsl_lpuart.h"
|
||||
#include "fsl_iomuxc.h"
|
||||
|
||||
#define DEFAULT_UART_BAUDRATE (115200)
|
||||
#define DEFAULT_BUFFER_SIZE (256)
|
||||
#define MIN_BUFFER_SIZE (32)
|
||||
#define MAX_BUFFER_SIZE (32766)
|
||||
|
||||
#define UART_INVERT_TX (1)
|
||||
#define UART_INVERT_RX (2)
|
||||
#define UART_INVERT_MASK (UART_INVERT_TX | UART_INVERT_RX)
|
||||
|
||||
typedef struct _machine_uart_obj_t {
|
||||
mp_obj_base_t base;
|
||||
struct _lpuart_handle handle;
|
||||
lpuart_config_t config;
|
||||
LPUART_Type *lpuart;
|
||||
uint16_t timeout; // timeout waiting for first char (in ms)
|
||||
uint16_t timeout_char; // timeout waiting between chars (in ms)
|
||||
uint8_t id;
|
||||
uint8_t invert;
|
||||
uint16_t tx_status;
|
||||
uint8_t *txbuf;
|
||||
uint16_t txbuf_len;
|
||||
bool new;
|
||||
} machine_uart_obj_t;
|
||||
|
||||
typedef struct _iomux_table_t {
|
||||
uint32_t muxRegister;
|
||||
uint32_t muxMode;
|
||||
uint32_t inputRegister;
|
||||
uint32_t inputDaisy;
|
||||
uint32_t configRegister;
|
||||
} iomux_table_t;
|
||||
|
||||
extern const mp_obj_type_t machine_uart_type;
|
||||
|
||||
STATIC const uint8_t uart_index_table[] = MICROPY_HW_UART_INDEX;
|
||||
STATIC LPUART_Type *uart_base_ptr_table[] = LPUART_BASE_PTRS;
|
||||
static const iomux_table_t iomux_table_uart[] = {
|
||||
IOMUX_TABLE_UART
|
||||
};
|
||||
|
||||
STATIC const char *_parity_name[] = {"None", "", "0", "1"}; // Is defined as 0, 2, 3
|
||||
STATIC const char *_invert_name[] = {"None", "INV_TX", "INV_RX", "INV_TX|INV_RX"};
|
||||
|
||||
#define RX (iomux_table_uart[index + 1])
|
||||
#define TX (iomux_table_uart[index])
|
||||
|
||||
bool lpuart_set_iomux(int8_t uart) {
|
||||
int index = (uart - 1) * 2;
|
||||
|
||||
if (TX.muxRegister != 0) {
|
||||
IOMUXC_SetPinMux(TX.muxRegister, TX.muxMode, TX.inputRegister, TX.inputDaisy, TX.configRegister, 0U);
|
||||
IOMUXC_SetPinConfig(TX.muxRegister, TX.muxMode, TX.inputRegister, TX.inputDaisy, TX.configRegister, 0x10B0u);
|
||||
|
||||
IOMUXC_SetPinMux(RX.muxRegister, RX.muxMode, RX.inputRegister, RX.inputDaisy, RX.configRegister, 0U);
|
||||
IOMUXC_SetPinConfig(RX.muxRegister, RX.muxMode, RX.inputRegister, RX.inputDaisy, RX.configRegister, 0x10B0u);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t UART_SrcFreq(void) {
|
||||
uint32_t freq;
|
||||
// To make it simple, we assume default PLL and divider settings, and the
|
||||
// only variable from application is use PLL3 source or OSC source.
|
||||
if (CLOCK_GetMux(kCLOCK_UartMux) == 0) { // PLL3 div6 80M
|
||||
freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
|
||||
} else {
|
||||
freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
|
||||
void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, status_t status, void *userData) {
|
||||
machine_uart_obj_t *self = userData;
|
||||
if (kStatus_LPUART_TxIdle == status) {
|
||||
self->tx_status = kStatus_LPUART_TxIdle;
|
||||
}
|
||||
|
||||
if (kStatus_LPUART_RxRingBufferOverrun == status) {
|
||||
; // Ringbuffer full, deassert RTS if flow control is enabled
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, "
|
||||
"rxbuf=%d, txbuf=%d, timeout=%u, timeout_char=%u, invert=%s)",
|
||||
self->id, self->config.baudRate_Bps, 8 - self->config.dataBitsCount,
|
||||
_parity_name[self->config.parityMode], self->config.stopBitCount + 1,
|
||||
self->handle.rxRingBufferSize, self->txbuf_len, self->timeout, self->timeout_char,
|
||||
_invert_name[self->invert]);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop,
|
||||
ARG_timeout, ARG_timeout_char, ARG_invert, ARG_rxbuf, ARG_txbuf};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_parity, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(-1)} },
|
||||
{ MP_QSTR_stop, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_txbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
|
||||
// Parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// Set baudrate if configured.
|
||||
if (args[ARG_baudrate].u_int > 0) {
|
||||
self->config.baudRate_Bps = args[ARG_baudrate].u_int;
|
||||
}
|
||||
|
||||
// Set bits if configured.
|
||||
if (args[ARG_bits].u_int > 0) {
|
||||
self->config.dataBitsCount = 8 - args[ARG_bits].u_int;
|
||||
}
|
||||
|
||||
// Set parity if configured.
|
||||
if (args[ARG_parity].u_obj != MP_OBJ_NEW_SMALL_INT(-1)) {
|
||||
if (args[ARG_parity].u_obj == mp_const_none) {
|
||||
self->config.parityMode = kLPUART_ParityDisabled;
|
||||
} else if (mp_obj_get_int(args[ARG_parity].u_obj) & 1) {
|
||||
self->config.parityMode = kLPUART_ParityOdd;
|
||||
} else {
|
||||
self->config.parityMode = kLPUART_ParityEven;
|
||||
}
|
||||
}
|
||||
|
||||
// Set stop bits if configured.
|
||||
if (args[ARG_stop].u_int > 0) {
|
||||
self->config.stopBitCount = args[ARG_stop].u_int - 1;
|
||||
}
|
||||
|
||||
// Set timeout if configured.
|
||||
if (args[ARG_timeout].u_int >= 0) {
|
||||
self->timeout = args[ARG_timeout].u_int;
|
||||
}
|
||||
|
||||
// Set timeout_char if configured.
|
||||
if (args[ARG_timeout_char].u_int >= 0) {
|
||||
self->timeout_char = args[ARG_timeout_char].u_int;
|
||||
}
|
||||
|
||||
// Set line inversion if configured.
|
||||
if (args[ARG_invert].u_int >= 0) {
|
||||
if (args[ARG_invert].u_int & ~UART_INVERT_MASK) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bad inversion mask"));
|
||||
}
|
||||
self->invert = args[ARG_invert].u_int;
|
||||
}
|
||||
|
||||
self->tx_status = kStatus_LPUART_TxIdle;
|
||||
self->config.enableTx = true;
|
||||
self->config.enableRx = true;
|
||||
|
||||
// Set the RX buffer size if configured.
|
||||
size_t rxbuf_len = DEFAULT_BUFFER_SIZE;
|
||||
if (args[ARG_rxbuf].u_int > 0) {
|
||||
rxbuf_len = args[ARG_rxbuf].u_int;
|
||||
if (rxbuf_len < MIN_BUFFER_SIZE) {
|
||||
rxbuf_len = MIN_BUFFER_SIZE;
|
||||
} else if (rxbuf_len > MAX_BUFFER_SIZE) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("rxbuf too large"));
|
||||
}
|
||||
}
|
||||
|
||||
// Set the TX buffer size if configured.
|
||||
size_t txbuf_len = DEFAULT_BUFFER_SIZE;
|
||||
if (args[ARG_txbuf].u_int > 0) {
|
||||
txbuf_len = args[ARG_txbuf].u_int;
|
||||
if (txbuf_len < MIN_BUFFER_SIZE) {
|
||||
txbuf_len = MIN_BUFFER_SIZE;
|
||||
} else if (txbuf_len > MAX_BUFFER_SIZE) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("txbuf too large"));
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise the UART peripheral if any arguments given, or it was not initialised previously.
|
||||
if (n_args > 1 || self->new) {
|
||||
self->new = false;
|
||||
// may be obsolete
|
||||
if (self->config.baudRate_Bps == 0) {
|
||||
self->config.baudRate_Bps = DEFAULT_UART_BAUDRATE;
|
||||
}
|
||||
|
||||
// Make sure timeout_char is at least as long as a whole character (13 bits to be safe).
|
||||
uint32_t min_timeout_char = 13000 / self->config.baudRate_Bps + 1;
|
||||
if (self->timeout_char < min_timeout_char) {
|
||||
self->timeout_char = min_timeout_char;
|
||||
}
|
||||
|
||||
LPUART_Init(self->lpuart, &self->config, UART_SrcFreq()); // ??
|
||||
LPUART_TransferCreateHandle(self->lpuart, &self->handle, LPUART_UserCallback, self);
|
||||
uint8_t *buffer = m_new(uint8_t, rxbuf_len + 1);
|
||||
LPUART_TransferStartRingBuffer(self->lpuart, &self->handle, buffer, rxbuf_len);
|
||||
self->txbuf = m_new(uint8_t, txbuf_len); // Allocate the TX buffer.
|
||||
self->txbuf_len = txbuf_len;
|
||||
|
||||
// The Uart supports inverting, but not the fsl API, so it has to coded directly
|
||||
// And it has to be done after LPUART_Init.
|
||||
if (self->invert & UART_INVERT_RX) {
|
||||
LPUART_EnableRx(self->lpuart, false);
|
||||
self->lpuart->STAT |= 1 << LPUART_STAT_RXINV_SHIFT;
|
||||
LPUART_EnableRx(self->lpuart, true);
|
||||
}
|
||||
if (self->invert & UART_INVERT_TX) {
|
||||
LPUART_EnableTx(self->lpuart, false);
|
||||
self->lpuart->CTRL |= 1 << LPUART_CTRL_TXINV_SHIFT;
|
||||
LPUART_EnableTx(self->lpuart, true);
|
||||
}
|
||||
// Send long break; drop that code for a shorter break duration
|
||||
LPUART_EnableTx(self->lpuart, false);
|
||||
self->lpuart->STAT |= 1 << LPUART_STAT_BRK13_SHIFT;
|
||||
LPUART_EnableTx(self->lpuart, true);
|
||||
|
||||
// Allocate the TX ring buffer. Not used yet, but maybe later.
|
||||
|
||||
// ringbuf_alloc(&(self->write_buffer), txbuf_len + 1);
|
||||
// MP_STATE_PORT(rp2_uart_tx_buffer[uart_id]) = self->write_buffer.buf;
|
||||
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_uart_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, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
|
||||
// Get UART bus.
|
||||
int uart_id = mp_obj_get_int(args[0]);
|
||||
if (uart_id < 1 || uart_id > MICROPY_HW_UART_NUM) {
|
||||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("UART(%d) doesn't exist"), uart_id);
|
||||
}
|
||||
|
||||
// Create the UART object and fill it with defaults.
|
||||
uint8_t uart_hw_id = uart_index_table[uart_id]; // the hw uart number 1..n
|
||||
machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t);
|
||||
self->base.type = &machine_uart_type;
|
||||
self->id = uart_id;
|
||||
self->lpuart = uart_base_ptr_table[uart_hw_id];
|
||||
self->invert = false;
|
||||
self->timeout = 1;
|
||||
self->timeout_char = 1;
|
||||
self->new = true;
|
||||
LPUART_GetDefaultConfig(&self->config);
|
||||
|
||||
// Configure board-specific pin MUX based on the hardware device number.
|
||||
lpuart_set_iomux(uart_hw_id);
|
||||
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
return machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
|
||||
}
|
||||
|
||||
// uart.init(baud, [kwargs])
|
||||
STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
return machine_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init);
|
||||
|
||||
STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
size_t count = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle);
|
||||
return MP_OBJ_NEW_SMALL_INT(count);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any);
|
||||
|
||||
STATIC mp_obj_t machine_uart_sendbreak(mp_obj_t self_in) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
self->lpuart->CTRL |= 1 << LPUART_CTRL_SBK_SHIFT; // Set SBK bit
|
||||
self->lpuart->CTRL &= ~LPUART_CTRL_SBK_MASK; // Clear SBK bit
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_sendbreak_obj, machine_uart_sendbreak);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_uart_sendbreak_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_INV_TX), MP_ROM_INT(UART_INVERT_TX) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INV_RX), MP_ROM_INT(UART_INVERT_RX) },
|
||||
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table);
|
||||
|
||||
STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uint64_t t = ticks_us64() + (uint64_t)self->timeout * 1000;
|
||||
uint64_t timeout_char_us = (uint64_t)self->timeout_char * 1000;
|
||||
lpuart_transfer_t xfer;
|
||||
uint8_t *dest = buf_in;
|
||||
size_t avail;
|
||||
size_t nget;
|
||||
|
||||
for (size_t received = 0; received < size;) {
|
||||
// Wait for the first/next character.
|
||||
while ((avail = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle)) <= 0) {
|
||||
if (ticks_us64() > t) { // timed out
|
||||
if (received <= 0) {
|
||||
*errcode = MP_EAGAIN;
|
||||
return MP_STREAM_ERROR;
|
||||
} else {
|
||||
return received;
|
||||
}
|
||||
}
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
}
|
||||
// Get as many bytes as possible to meet the need.
|
||||
nget = avail < (size - received) ? avail : size - received;
|
||||
xfer.data = dest + received;
|
||||
xfer.dataSize = nget;
|
||||
LPUART_TransferReceiveNonBlocking(self->lpuart, &self->handle, &xfer, NULL);
|
||||
received += nget;
|
||||
t = ticks_us64() + timeout_char_us;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
lpuart_transfer_t xfer;
|
||||
uint64_t t;
|
||||
size_t remaining = size;
|
||||
size_t offset = 0;
|
||||
uint8_t fifo_size = FSL_FEATURE_LPUART_FIFO_SIZEn(0);
|
||||
|
||||
// First check if a previous transfer is still ongoing,
|
||||
// then wait at least the number of remaining character times.
|
||||
t = ticks_us64() + (uint64_t)(self->handle.txDataSize + fifo_size) * (13000000 / self->config.baudRate_Bps + 1000);
|
||||
while (self->tx_status != kStatus_LPUART_TxIdle) {
|
||||
if (ticks_us64() > t) { // timed out, hard error
|
||||
*errcode = MP_ETIMEDOUT;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
}
|
||||
|
||||
// Check if the first part has to be sent semi-blocking.
|
||||
if (size > self->txbuf_len) {
|
||||
// Send the first block.
|
||||
xfer.data = (uint8_t *)buf_in;
|
||||
offset = xfer.dataSize = size - self->txbuf_len;
|
||||
self->tx_status = kStatus_LPUART_TxBusy;
|
||||
LPUART_TransferSendNonBlocking(self->lpuart, &self->handle, &xfer);
|
||||
|
||||
// Wait at least the number of character times for this chunk.
|
||||
t = ticks_us64() + (uint64_t)xfer.dataSize * (13000000 / self->config.baudRate_Bps + 1000);
|
||||
while (self->handle.txDataSize) {
|
||||
// Wait for the first/next character to be sent.
|
||||
if (ticks_us64() > t) { // timed out
|
||||
if (self->handle.txDataSize >= size) {
|
||||
*errcode = MP_ETIMEDOUT;
|
||||
return MP_STREAM_ERROR;
|
||||
} else {
|
||||
return size - self->handle.txDataSize;
|
||||
}
|
||||
}
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
}
|
||||
remaining = self->txbuf_len;
|
||||
} else {
|
||||
// The data fits into the tx buffer.
|
||||
offset = 0;
|
||||
remaining = size;
|
||||
}
|
||||
|
||||
// Send the remaining data without waiting for completion.
|
||||
memcpy(self->txbuf, (uint8_t *)buf_in + offset, remaining);
|
||||
xfer.data = self->txbuf;
|
||||
xfer.dataSize = remaining;
|
||||
self->tx_status = kStatus_LPUART_TxBusy;
|
||||
LPUART_TransferSendNonBlocking(self->lpuart, &self->handle, &xfer);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
|
||||
machine_uart_obj_t *self = self_in;
|
||||
mp_uint_t ret;
|
||||
if (request == MP_STREAM_POLL) {
|
||||
uintptr_t flags = arg;
|
||||
ret = 0;
|
||||
if (flags & MP_STREAM_POLL_RD) {
|
||||
uint32_t count;
|
||||
count = LPUART_TransferGetRxRingBufferLength(self->lpuart, &self->handle);
|
||||
if (count > 0) {
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
}
|
||||
if ((flags & MP_STREAM_POLL_WR)) {
|
||||
ret |= MP_STREAM_POLL_WR;
|
||||
}
|
||||
} else {
|
||||
*errcode = MP_EINVAL;
|
||||
ret = MP_STREAM_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC const mp_stream_p_t uart_stream_p = {
|
||||
.read = machine_uart_read,
|
||||
.write = machine_uart_write,
|
||||
.ioctl = machine_uart_ioctl,
|
||||
.is_text = false,
|
||||
};
|
||||
|
||||
const mp_obj_type_t machine_uart_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_UART,
|
||||
.print = machine_uart_print,
|
||||
.make_new = machine_uart_make_new,
|
||||
.getiter = mp_identity_getiter,
|
||||
.iternext = mp_stream_unbuffered_iter,
|
||||
.protocol = &uart_stream_p,
|
||||
.locals_dict = (mp_obj_dict_t *)&machine_uart_locals_dict,
|
||||
};
|
||||
@ -36,6 +36,7 @@
|
||||
#include "ticks.h"
|
||||
#include "tusb.h"
|
||||
#include "led.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
extern uint8_t _sstack, _estack, _gc_heap_start, _gc_heap_end;
|
||||
|
||||
@ -69,7 +70,8 @@ int main(void) {
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
goto soft_reset_exit;
|
||||
}
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
|
||||
// Do not execute main.py if boot.py failed
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL && ret != 0) {
|
||||
ret = pyexec_file_if_exists("main.py");
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
goto soft_reset_exit;
|
||||
@ -90,6 +92,7 @@ int main(void) {
|
||||
|
||||
soft_reset_exit:
|
||||
mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
|
||||
machine_pin_irq_deinit();
|
||||
gc_sweep_all();
|
||||
mp_deinit();
|
||||
}
|
||||
@ -128,8 +131,23 @@ const char mimxrt_help_text[] =
|
||||
" machine.Pin(pin, m, [p]) -- get a pin and configure it for IO mode m, pull mode p\n"
|
||||
" methods: init(..), value([v]), high(), low())\n"
|
||||
"\n"
|
||||
"Pin IO modes are: Pin.IN, Pin.OUT, Pin.OPEN_DRAIN\n"
|
||||
"Pin pull modes are: Pin.PULL_UP, Pin.PULL_UP_47K, Pin.PULL_UP_22K, Pin.PULL_DOWN, Pin.PULL_HOLD\n"
|
||||
" Pins are numbered board specific, either 0-n, or 'D0'-'Dn', or 'A0' - 'An',\n"
|
||||
" according to the boards's pinout sheet.\n"
|
||||
" Pin IO modes are: Pin.IN, Pin.OUT, Pin.OPEN_DRAIN\n"
|
||||
" Pin pull modes are: Pin.PULL_UP, Pin.PULL_UP_47K, Pin.PULL_UP_22K, Pin.PULL_DOWN, Pin.PULL_HOLD\n"
|
||||
" machine.ADC(pin) -- make an analog object from a pin\n"
|
||||
" methods: read_u16()\n"
|
||||
" machine.UART(id, baudrate=115200) -- create an UART object (id=1 - 8)\n"
|
||||
" methods: init(), write(buf), any()\n"
|
||||
" buf=read(n), readinto(buf), buf=readline()\n"
|
||||
" The RX and TX pins are fixed and board-specific.\n"
|
||||
" machine.SoftI2C() -- create an Soft I2C object\n"
|
||||
" methods: readfrom(addr, buf, stop=True), writeto(addr, buf, stop=True)\n"
|
||||
" readfrom_mem(addr, memaddr, arg), writeto_mem(addr, memaddr, arg)\n"
|
||||
" machine.SoftSPI(baudrate=1000000) -- create an SPI object ()\n"
|
||||
" methods: read(nbytes, write=0x00), write(buf), write_readinto(wr_buf, rd_buf)\n"
|
||||
" machine.Timer(id, freq, callback) -- create a hardware timer object (id=0,1,2)\n"
|
||||
" eg: machine.Timer(freq=1, callback=lambda t:print(t))\n"
|
||||
"\n"
|
||||
"Useful control commands:\n"
|
||||
" CTRL-C -- interrupt a running program\n"
|
||||
|
||||
@ -127,13 +127,6 @@ STATIC mp_obj_t mimxrt_flash_readblocks(size_t n_args, const mp_obj_t *args) {
|
||||
mimxrt_flash_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);
|
||||
// if (n_args == 4) {
|
||||
// mp_printf(MP_PYTHON_PRINTER, "readblocks: nargs = %d, block = %d, offset = %d, len = %d\n",
|
||||
// n_args, mp_obj_get_int(args[1]), mp_obj_get_int(args[3]), bufinfo.len);
|
||||
// } else {
|
||||
// mp_printf(MP_PYTHON_PRINTER, "readblocks: nargs = %d, block = %d, len = %d\n",
|
||||
// n_args, mp_obj_get_int(args[1]), bufinfo.len);
|
||||
// }
|
||||
// Calculate read offset from block number.
|
||||
uint32_t offset = mp_obj_get_int(args[1]) * SECTOR_SIZE_BYTES;
|
||||
// Add optional offset
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/machine_mem.h"
|
||||
#include "extmod/machine_i2c.h"
|
||||
#include "extmod/machine_pulse.h"
|
||||
#include "extmod/machine_signal.h"
|
||||
#include "extmod/machine_spi.h"
|
||||
#include "led.h"
|
||||
@ -48,6 +49,25 @@ STATIC mp_obj_t machine_freq(void) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);
|
||||
|
||||
STATIC mp_obj_t machine_idle(void) {
|
||||
MICROPY_EVENT_POLL_HOOK;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
|
||||
|
||||
STATIC mp_obj_t machine_disable_irq(void) {
|
||||
uint32_t state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
return mp_obj_new_int(state);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq);
|
||||
|
||||
STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) {
|
||||
uint32_t state = mp_obj_get_int(state_in);
|
||||
MICROPY_END_ATOMIC_SECTION(state);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
|
||||
@ -65,6 +85,15 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
|
||||
|
||||
|
||||
@ -32,8 +32,11 @@
|
||||
extern const mp_obj_type_t machine_adc_type;
|
||||
extern const mp_obj_type_t machine_timer_type;
|
||||
extern const mp_obj_type_t machine_rtc_type;
|
||||
extern const mp_obj_type_t machine_spi_type;
|
||||
extern const mp_obj_type_t machine_uart_type;
|
||||
|
||||
void machine_adc_init(void);
|
||||
void machine_pin_irq_deinit(void);
|
||||
void machine_timer_init_PIT(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_MIMXRT_MODMACHINE_H
|
||||
|
||||
@ -61,21 +61,34 @@ STATIC mp_obj_t os_uname(void) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
|
||||
|
||||
STATIC mp_obj_t os_urandom(mp_obj_t num) {
|
||||
mp_int_t n = mp_obj_get_int(num);
|
||||
static bool initialized = false;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, n);
|
||||
static bool initialized = false;
|
||||
|
||||
STATIC void trng_start(void) {
|
||||
trng_config_t trngConfig;
|
||||
|
||||
if (!initialized) {
|
||||
trng_config_t trngConfig;
|
||||
|
||||
TRNG_GetDefaultConfig(&trngConfig);
|
||||
trngConfig.sampleMode = kTRNG_SampleModeVonNeumann;
|
||||
|
||||
TRNG_Init(TRNG, &trngConfig);
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t trng_random_u32(void) {
|
||||
uint32_t rngval;
|
||||
|
||||
trng_start();
|
||||
TRNG_GetRandomData(TRNG, (uint8_t *)&rngval, 4);
|
||||
return rngval;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t os_urandom(mp_obj_t num) {
|
||||
mp_int_t n = mp_obj_get_int(num);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, n);
|
||||
|
||||
trng_start();
|
||||
TRNG_GetRandomData(TRNG, vstr.buf, n);
|
||||
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
|
||||
@ -25,11 +25,90 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "extmod/utime_mphal.h"
|
||||
#include "fsl_snvs_lp.h"
|
||||
|
||||
// localtime([secs])
|
||||
// Convert a time expressed in seconds since the Epoch into an 8-tuple which
|
||||
// contains: (year, month, mday, hour, minute, second, weekday, yearday)
|
||||
// If secs is not provided or None, then the current time from the RTC is used.
|
||||
STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0 || args[0] == mp_const_none) {
|
||||
// Get current date and time.
|
||||
snvs_lp_srtc_datetime_t t;
|
||||
SNVS_LP_SRTC_GetDatetime(SNVS, &t);
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(t.year),
|
||||
mp_obj_new_int(t.month),
|
||||
mp_obj_new_int(t.day),
|
||||
mp_obj_new_int(t.hour),
|
||||
mp_obj_new_int(t.minute),
|
||||
mp_obj_new_int(t.second),
|
||||
mp_obj_new_int(timeutils_calc_weekday(t.year, t.month, t.day)),
|
||||
mp_obj_new_int(timeutils_year_day(t.year, t.month, t.day)),
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
} else {
|
||||
// Convert given seconds to tuple.
|
||||
mp_int_t seconds = mp_obj_get_int(args[0]);
|
||||
timeutils_struct_time_t tm;
|
||||
timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
|
||||
mp_obj_t tuple[8] = {
|
||||
tuple[0] = mp_obj_new_int(tm.tm_year),
|
||||
tuple[1] = mp_obj_new_int(tm.tm_mon),
|
||||
tuple[2] = mp_obj_new_int(tm.tm_mday),
|
||||
tuple[3] = mp_obj_new_int(tm.tm_hour),
|
||||
tuple[4] = mp_obj_new_int(tm.tm_min),
|
||||
tuple[5] = mp_obj_new_int(tm.tm_sec),
|
||||
tuple[6] = mp_obj_new_int(tm.tm_wday),
|
||||
tuple[7] = mp_obj_new_int(tm.tm_yday),
|
||||
};
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
}
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
|
||||
|
||||
// mktime()
|
||||
// This is inverse function of localtime. It's argument is a full 8-tuple
|
||||
// which expresses a time as per localtime. It returns an integer which is
|
||||
// the number of seconds since the Epoch.
|
||||
STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
|
||||
size_t len;
|
||||
mp_obj_t *elem;
|
||||
mp_obj_get_array(tuple, &len, &elem);
|
||||
|
||||
// localtime generates a tuple of len 8. CPython uses 9, so we accept both.
|
||||
if (len < 8 || len > 9) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9"));
|
||||
}
|
||||
|
||||
return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
|
||||
mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
|
||||
mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
|
||||
|
||||
// time()
|
||||
// Return the number of seconds since the Epoch.
|
||||
STATIC mp_obj_t time_time(void) {
|
||||
snvs_lp_srtc_datetime_t t;
|
||||
SNVS_LP_SRTC_GetDatetime(SNVS, &t);
|
||||
return mp_obj_new_int_from_ull(timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.minute, t.second));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
|
||||
|
||||
STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&time_localtime_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_time_ns), MP_ROM_PTR(&mp_utime_time_ns_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
|
||||
|
||||
@ -30,6 +30,8 @@
|
||||
#include "mpconfigboard.h"
|
||||
#include "fsl_common.h"
|
||||
|
||||
uint32_t trng_random_u32(void);
|
||||
|
||||
// Memory allocation policies
|
||||
#define MICROPY_GC_STACK_ENTRY_TYPE uint16_t
|
||||
#define MICROPY_GC_ALLOC_THRESHOLD (0)
|
||||
@ -118,9 +120,11 @@
|
||||
#define MICROPY_PY_UTIME_MP_HAL (1)
|
||||
#define MICROPY_PY_URANDOM (1)
|
||||
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
|
||||
#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (trng_random_u32())
|
||||
#define MICROPY_PY_USELECT (1)
|
||||
#define MICROPY_PY_MACHINE (1)
|
||||
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
|
||||
#define MICROPY_PY_MACHINE_PULSE (1)
|
||||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_SPI (1)
|
||||
#define MICROPY_PY_FRAMEBUF (1)
|
||||
@ -167,7 +171,8 @@ extern const struct _mp_obj_module_t mp_module_utime;
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8]; \
|
||||
struct _machine_timer_obj_t *timer_table[MICROPY_HW_PIT_NUM_CHANNELS];
|
||||
struct _machine_timer_obj_t *timer_table[MICROPY_HW_PIT_NUM_CHANNELS]; \
|
||||
void *machine_pin_irq_objects[MICROPY_HW_NUM_PIN_IRQS]; \
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
|
||||
@ -28,8 +28,10 @@
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mphal.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "ticks.h"
|
||||
#include "tusb.h"
|
||||
#include "fsl_snvs_lp.h"
|
||||
|
||||
#include CPU_HEADER_H
|
||||
|
||||
@ -94,3 +96,10 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
|
||||
// USARTx->USART.DATA.bit.DATA = *str++;
|
||||
// }
|
||||
}
|
||||
|
||||
uint64_t mp_hal_time_ns(void) {
|
||||
snvs_lp_srtc_datetime_t t;
|
||||
SNVS_LP_SRTC_GetDatetime(SNVS, &t);
|
||||
uint64_t s = timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.minute, t.second);
|
||||
return s * 1000000000ULL;
|
||||
}
|
||||
|
||||
@ -76,9 +76,5 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint64_t mp_hal_time_ns(void) {
|
||||
// TODO: Implement this function.
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
#endif // MICROPY_INCLUDED_MIMXRT_MPHALPORT_H
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "py/obj.h"
|
||||
#include "lib/utils/mpirq.h"
|
||||
#include "fsl_gpio.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------ //
|
||||
@ -118,6 +119,12 @@ typedef struct {
|
||||
const machine_pin_adc_obj_t *adc_list; // pointer to list with ADC options
|
||||
} machine_pin_obj_t;
|
||||
|
||||
typedef struct _machine_pin_irq_obj_t {
|
||||
mp_irq_obj_t base;
|
||||
uint32_t flags;
|
||||
uint32_t trigger;
|
||||
} machine_pin_irq_obj_t;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------ //
|
||||
|
||||
extern const mp_obj_type_t machine_pin_type;
|
||||
|
||||
@ -149,7 +149,7 @@ STATIC void async_stop(void) {
|
||||
STATIC void wait_for_event(void) {
|
||||
while (!wakeup_event) {
|
||||
// allow CTRL-C to stop the animation
|
||||
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
|
||||
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
|
||||
async_stop();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ STATIC void wait_async_music_idle(void) {
|
||||
// wait for the async music state to become idle
|
||||
while (music_data->async_state != ASYNC_MUSIC_STATE_IDLE) {
|
||||
// allow CTRL-C to stop the music
|
||||
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
|
||||
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
|
||||
music_data->async_state = ASYNC_MUSIC_STATE_IDLE;
|
||||
pwm_set_duty_cycle(music_data->async_pin->pin, 0); // TODO: remove pin setting.
|
||||
break;
|
||||
|
||||
@ -140,7 +140,7 @@ int switch_get(int sw) {
|
||||
// TODO need an irq
|
||||
void uart_rx_irq(void) {
|
||||
if (c == interrupt_char) {
|
||||
MP_STATE_VM(mp_pending_exception) = MP_STATE_PORT(keyboard_interrupt_obj);
|
||||
MP_STATE_MAIN_THREAD(mp_pending_exception) = MP_STATE_PORT(keyboard_interrupt_obj);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@ -86,6 +86,7 @@ set(MICROPY_SOURCE_PORT
|
||||
machine_i2c.c
|
||||
machine_pin.c
|
||||
machine_pwm.c
|
||||
machine_rtc.c
|
||||
machine_spi.c
|
||||
machine_timer.c
|
||||
machine_uart.c
|
||||
@ -113,6 +114,7 @@ set(MICROPY_SOURCE_QSTR
|
||||
${PROJECT_SOURCE_DIR}/machine_i2c.c
|
||||
${PROJECT_SOURCE_DIR}/machine_pin.c
|
||||
${PROJECT_SOURCE_DIR}/machine_pwm.c
|
||||
${PROJECT_SOURCE_DIR}/machine_rtc.c
|
||||
${PROJECT_SOURCE_DIR}/machine_spi.c
|
||||
${PROJECT_SOURCE_DIR}/machine_timer.c
|
||||
${PROJECT_SOURCE_DIR}/machine_uart.c
|
||||
@ -154,6 +156,7 @@ set(PICO_SDK_COMPONENTS
|
||||
pico_sync
|
||||
pico_time
|
||||
pico_unique_id
|
||||
pico_util
|
||||
tinyusb_common
|
||||
tinyusb_device
|
||||
)
|
||||
|
||||
123
ports/rp2/machine_rtc.c
Normal file
123
ports/rp2/machine_rtc.c
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 "Krzysztof Adamski" <k@japko.eu>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "hardware/rtc.h"
|
||||
#include "pico/util/datetime.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
typedef struct _machine_rtc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
} machine_rtc_obj_t;
|
||||
|
||||
// singleton RTC object
|
||||
STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}};
|
||||
|
||||
STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
bool r = rtc_running();
|
||||
|
||||
if (!r) {
|
||||
// This shouldn't happen as rtc_init() is already called in main so
|
||||
// it's here just in case
|
||||
rtc_init();
|
||||
datetime_t t = { .month = 1, .day = 1 };
|
||||
rtc_set_datetime(&t);
|
||||
}
|
||||
// return constant object
|
||||
return (mp_obj_t)&machine_rtc_obj;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 1) {
|
||||
bool ret;
|
||||
datetime_t t;
|
||||
|
||||
ret = rtc_get_datetime(&t);
|
||||
if (!ret) {
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(t.year),
|
||||
mp_obj_new_int(t.month),
|
||||
mp_obj_new_int(t.day),
|
||||
mp_obj_new_int(t.dotw),
|
||||
mp_obj_new_int(t.hour),
|
||||
mp_obj_new_int(t.min),
|
||||
mp_obj_new_int(t.sec),
|
||||
mp_obj_new_int(0)
|
||||
};
|
||||
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
} else {
|
||||
mp_obj_t *items;
|
||||
|
||||
mp_obj_get_array_fixed_n(args[1], 8, &items);
|
||||
|
||||
datetime_t t = {
|
||||
.year = mp_obj_get_int(items[0]),
|
||||
.month = mp_obj_get_int(items[1]),
|
||||
.day = mp_obj_get_int(items[2]),
|
||||
.hour = mp_obj_get_int(items[4]),
|
||||
.min = mp_obj_get_int(items[5]),
|
||||
.sec = mp_obj_get_int(items[6]),
|
||||
};
|
||||
// Deliberately ignore the weekday argument and compute the proper value
|
||||
t.dotw = timeutils_calc_weekday(t.year, t.month, t.day);
|
||||
|
||||
if (!rtc_set_datetime(&t)) {
|
||||
mp_raise_OSError(MP_EINVAL);
|
||||
}
|
||||
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t machine_rtc_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_RTC,
|
||||
.make_new = machine_rtc_make_new,
|
||||
.locals_dict = (mp_obj_t)&machine_rtc_locals_dict,
|
||||
};
|
||||
@ -80,7 +80,7 @@ int main(int argc, char **argv) {
|
||||
.year = 2021,
|
||||
.month = 1,
|
||||
.day = 1,
|
||||
.dotw = 5, // 0 is Sunday, so 5 is Friday
|
||||
.dotw = 4, // 0 is Monday, so 4 is Friday
|
||||
.hour = 0,
|
||||
.min = 0,
|
||||
.sec = 0,
|
||||
|
||||
@ -164,6 +164,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
|
||||
|
||||
@ -7,6 +7,7 @@ extern const mp_obj_type_t machine_adc_type;
|
||||
extern const mp_obj_type_t machine_hw_i2c_type;
|
||||
extern const mp_obj_type_t machine_pin_type;
|
||||
extern const mp_obj_type_t machine_pwm_type;
|
||||
extern const mp_obj_type_t machine_rtc_type;
|
||||
extern const mp_obj_type_t machine_spi_type;
|
||||
extern const mp_obj_type_t machine_timer_type;
|
||||
extern const mp_obj_type_t machine_uart_type;
|
||||
|
||||
@ -132,6 +132,7 @@ void VCC_GND_F407VE_board_early_init(void);
|
||||
|
||||
extern const struct _mp_spiflash_config_t spiflash_config;
|
||||
extern struct _spi_bdev_t spi_bdev;
|
||||
#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1)
|
||||
#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
|
||||
(op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
|
||||
(op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
|
||||
|
||||
@ -140,6 +140,7 @@ void VCC_GND_F407ZG_board_early_init(void);
|
||||
|
||||
extern const struct _mp_spiflash_config_t spiflash_config;
|
||||
extern struct _spi_bdev_t spi_bdev;
|
||||
#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1)
|
||||
#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
|
||||
(op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
|
||||
(op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
#define PHY_BCR (0x0000)
|
||||
#define PHY_BCR_SOFT_RESET (0x8000)
|
||||
#define PHY_BCR_AUTONEG_EN (0x1000)
|
||||
#define PHY_BCR_POWER_DOWN (0x0800U)
|
||||
|
||||
#undef PHY_BSR
|
||||
#define PHY_BSR (0x0001)
|
||||
@ -188,17 +189,6 @@ STATIC uint32_t eth_phy_read(uint32_t reg) {
|
||||
void eth_init(eth_t *self, int mac_idx) {
|
||||
mp_hal_get_mac(mac_idx, &self->netif.hwaddr[0]);
|
||||
self->netif.hwaddr_len = 6;
|
||||
}
|
||||
|
||||
void eth_set_trace(eth_t *self, uint32_t value) {
|
||||
self->trace_flags = value;
|
||||
}
|
||||
|
||||
STATIC int eth_mac_init(eth_t *self) {
|
||||
// Configure MPU
|
||||
uint32_t irq_state = mpu_config_start();
|
||||
mpu_config_region(MPU_REGION_ETH, (uint32_t)ð_dma, MPU_CONFIG_ETH(MPU_REGION_SIZE_16KB));
|
||||
mpu_config_end(irq_state);
|
||||
|
||||
// Configure GPIO
|
||||
mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDC, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDC);
|
||||
@ -211,6 +201,27 @@ STATIC int eth_mac_init(eth_t *self) {
|
||||
mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TXD0);
|
||||
mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TXD1);
|
||||
|
||||
// Enable peripheral clock
|
||||
#if defined(STM32H7)
|
||||
__HAL_RCC_ETH1MAC_CLK_ENABLE();
|
||||
__HAL_RCC_ETH1TX_CLK_ENABLE();
|
||||
__HAL_RCC_ETH1RX_CLK_ENABLE();
|
||||
#else
|
||||
__HAL_RCC_ETH_CLK_ENABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
void eth_set_trace(eth_t *self, uint32_t value) {
|
||||
self->trace_flags = value;
|
||||
}
|
||||
|
||||
STATIC int eth_mac_init(eth_t *self) {
|
||||
// Configure MPU
|
||||
uint32_t irq_state = mpu_config_start();
|
||||
mpu_config_region(MPU_REGION_ETH, (uint32_t)ð_dma, MPU_CONFIG_ETH(MPU_REGION_SIZE_16KB));
|
||||
mpu_config_end(irq_state);
|
||||
|
||||
// Enable peripheral clock
|
||||
#if defined(STM32H7)
|
||||
__HAL_RCC_ETH1MAC_CLK_ENABLE();
|
||||
__HAL_RCC_ETH1TX_CLK_ENABLE();
|
||||
@ -780,17 +791,20 @@ int eth_link_status(eth_t *self) {
|
||||
return 2; // link no-ip;
|
||||
}
|
||||
} else {
|
||||
int s = eth_phy_read(0) | eth_phy_read(0x10) << 16;
|
||||
if (s == 0) {
|
||||
return 0; // link down
|
||||
if (eth_phy_read(PHY_BSR) & PHY_BSR_LINK_STATUS) {
|
||||
return 1; // link up
|
||||
} else {
|
||||
return 1; // link join
|
||||
return 0; // link down
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int eth_start(eth_t *self) {
|
||||
eth_lwip_deinit(self);
|
||||
|
||||
// Make sure Eth is Not in low power mode.
|
||||
eth_low_power_mode(self, false);
|
||||
|
||||
int ret = eth_mac_init(self);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@ -805,4 +819,29 @@ int eth_stop(eth_t *self) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void eth_low_power_mode(eth_t *self, bool enable) {
|
||||
(void)self;
|
||||
|
||||
// Enable eth clock
|
||||
#if defined(STM32H7)
|
||||
__HAL_RCC_ETH1MAC_CLK_ENABLE();
|
||||
#else
|
||||
__HAL_RCC_ETH_CLK_ENABLE();
|
||||
#endif
|
||||
|
||||
uint16_t bcr = eth_phy_read(PHY_BCR);
|
||||
if (enable) {
|
||||
// Enable low-power mode.
|
||||
eth_phy_write(PHY_BCR, bcr | PHY_BCR_POWER_DOWN);
|
||||
// Disable eth clock.
|
||||
#if defined(STM32H7)
|
||||
__HAL_RCC_ETH1MAC_CLK_DISABLE();
|
||||
#else
|
||||
__HAL_RCC_ETH_CLK_DISABLE();
|
||||
#endif
|
||||
} else {
|
||||
// Disable low-power mode.
|
||||
eth_phy_write(PHY_BCR, bcr & (~PHY_BCR_POWER_DOWN));
|
||||
}
|
||||
}
|
||||
#endif // defined(MICROPY_HW_ETH_MDC)
|
||||
|
||||
@ -35,5 +35,6 @@ struct netif *eth_netif(eth_t *self);
|
||||
int eth_link_status(eth_t *self);
|
||||
int eth_start(eth_t *self);
|
||||
int eth_stop(eth_t *self);
|
||||
void eth_low_power_mode(eth_t *self, bool enable);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_ETH_H
|
||||
|
||||
@ -54,6 +54,7 @@
|
||||
#endif
|
||||
|
||||
#include "boardctrl.h"
|
||||
#include "mpbthciport.h"
|
||||
#include "mpu.h"
|
||||
#include "rfcore.h"
|
||||
#include "systick.h"
|
||||
@ -440,8 +441,7 @@ void stm32_main(uint32_t reset_mode) {
|
||||
systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper);
|
||||
#endif
|
||||
#if MICROPY_PY_BLUETOOTH
|
||||
extern void mp_bluetooth_hci_systick(uint32_t ticks_ms);
|
||||
systick_enable_dispatch(SYSTICK_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_systick);
|
||||
mp_bluetooth_hci_init();
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_CYW43
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018-2020 Damien P. George
|
||||
* Copyright (c) 2018-2021 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -28,7 +28,8 @@
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/mpbthci.h"
|
||||
#include "extmod/modbluetooth.h"
|
||||
#include "systick.h"
|
||||
#include "mpbthciport.h"
|
||||
#include "softtimer.h"
|
||||
#include "pendsv.h"
|
||||
#include "lib/utils/mpirq.h"
|
||||
|
||||
@ -38,22 +39,48 @@
|
||||
|
||||
uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
|
||||
|
||||
// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
|
||||
// Request new data from the uart and pass to the stack, and run pending events/callouts.
|
||||
extern void mp_bluetooth_hci_poll(void);
|
||||
// Soft timer for scheduling a HCI poll.
|
||||
STATIC soft_timer_entry_t mp_bluetooth_hci_soft_timer;
|
||||
|
||||
// Hook for pendsv poller to run this periodically every 128ms
|
||||
#define BLUETOOTH_HCI_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0)
|
||||
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
||||
// Prevent double-enqueuing of the scheduled task.
|
||||
STATIC volatile bool events_task_is_scheduled;
|
||||
#endif
|
||||
|
||||
// This is called by soft_timer and executes at IRQ_PRI_PENDSV.
|
||||
STATIC void mp_bluetooth_hci_soft_timer_callback(soft_timer_entry_t *self) {
|
||||
mp_bluetooth_hci_poll_now();
|
||||
}
|
||||
|
||||
void mp_bluetooth_hci_init(void) {
|
||||
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
||||
events_task_is_scheduled = false;
|
||||
#endif
|
||||
soft_timer_static_init(
|
||||
&mp_bluetooth_hci_soft_timer,
|
||||
SOFT_TIMER_MODE_ONE_SHOT,
|
||||
0,
|
||||
mp_bluetooth_hci_soft_timer_callback
|
||||
);
|
||||
}
|
||||
|
||||
STATIC void mp_bluetooth_hci_start_polling(void) {
|
||||
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
||||
events_task_is_scheduled = false;
|
||||
#endif
|
||||
mp_bluetooth_hci_poll_now();
|
||||
}
|
||||
|
||||
void mp_bluetooth_hci_poll_in_ms(uint32_t ms) {
|
||||
soft_timer_reinsert(&mp_bluetooth_hci_soft_timer, ms);
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
||||
|
||||
// For synchronous mode, we run all BLE stack code inside a scheduled task.
|
||||
// This task is scheduled periodically (every 128ms) via SysTick, or
|
||||
// This task is scheduled periodically via a soft timer, or
|
||||
// immediately on HCI UART RXIDLE.
|
||||
|
||||
// Prevent double-enqueuing of the scheduled task.
|
||||
STATIC volatile bool events_task_is_scheduled = false;
|
||||
|
||||
STATIC mp_obj_t run_events_scheduled_task(mp_obj_t none_in) {
|
||||
(void)none_in;
|
||||
events_task_is_scheduled = false;
|
||||
@ -65,23 +92,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_sched
|
||||
|
||||
// Called periodically (systick) or directly (e.g. UART RX IRQ) in order to
|
||||
// request that processing happens ASAP in the scheduler.
|
||||
void mp_bluetooth_hci_systick(uint32_t ticks_ms) {
|
||||
if (events_task_is_scheduled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ticks_ms == 0 || BLUETOOTH_HCI_TICK(ticks_ms)) {
|
||||
void mp_bluetooth_hci_poll_now(void) {
|
||||
if (!events_task_is_scheduled) {
|
||||
events_task_is_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&run_events_scheduled_task_obj), mp_const_none);
|
||||
if (!events_task_is_scheduled) {
|
||||
// The schedule queue is full, set callback to try again soon.
|
||||
mp_bluetooth_hci_poll_in_ms(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
||||
|
||||
// Called periodically (systick) or directly (e.g. uart irq).
|
||||
void mp_bluetooth_hci_systick(uint32_t ticks_ms) {
|
||||
if (ticks_ms == 0 || BLUETOOTH_HCI_TICK(ticks_ms)) {
|
||||
pendsv_schedule_dispatch(PENDSV_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll);
|
||||
}
|
||||
void mp_bluetooth_hci_poll_now(void) {
|
||||
pendsv_schedule_dispatch(PENDSV_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -104,14 +128,13 @@ int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
|
||||
|
||||
DEBUG_printf("mp_bluetooth_hci_uart_init (stm32 rfcore)\n");
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
||||
events_task_is_scheduled = false;
|
||||
#endif
|
||||
|
||||
rfcore_ble_init();
|
||||
hci_uart_rx_buf_cur = 0;
|
||||
hci_uart_rx_buf_len = 0;
|
||||
|
||||
// Start the HCI polling to process any initial events/packets.
|
||||
mp_bluetooth_hci_start_polling();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -163,7 +186,6 @@ int mp_bluetooth_hci_uart_readchar(void) {
|
||||
/******************************************************************************/
|
||||
// HCI over UART
|
||||
|
||||
#include "pendsv.h"
|
||||
#include "uart.h"
|
||||
|
||||
pyb_uart_obj_t mp_bluetooth_hci_uart_obj;
|
||||
@ -173,7 +195,7 @@ static uint8_t hci_uart_rxbuf[768];
|
||||
|
||||
mp_obj_t mp_uart_interrupt(mp_obj_t self_in) {
|
||||
// Queue up the scheduler to run the HCI UART and event processing ASAP.
|
||||
mp_bluetooth_hci_systick(0);
|
||||
mp_bluetooth_hci_poll_now();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
@ -182,10 +204,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_uart_interrupt_obj, mp_uart_interrupt);
|
||||
int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
|
||||
DEBUG_printf("mp_bluetooth_hci_uart_init (stm32)\n");
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
||||
events_task_is_scheduled = false;
|
||||
#endif
|
||||
|
||||
// bits (8), stop (1), parity (none) and flow (rts/cts) are assumed to match MYNEWT_VAL_BLE_HCI_UART_ constants in syscfg.h.
|
||||
mp_bluetooth_hci_uart_obj.base.type = &pyb_uart_type;
|
||||
mp_bluetooth_hci_uart_obj.uart_id = port;
|
||||
@ -208,6 +226,9 @@ int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
|
||||
mp_bluetooth_hci_uart_irq_obj.ishard = true;
|
||||
uart_irq_config(&mp_bluetooth_hci_uart_obj, true);
|
||||
|
||||
// Start the HCI polling to process any initial events/packets.
|
||||
mp_bluetooth_hci_start_polling();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
42
ports/stm32/mpbthciport.h
Normal file
42
ports/stm32/mpbthciport.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
|
||||
#define MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
|
||||
|
||||
// Initialise the HCI subsystem (should be called once, early on).
|
||||
void mp_bluetooth_hci_init(void);
|
||||
|
||||
// Poll the HCI now, or after a certain timeout.
|
||||
void mp_bluetooth_hci_poll_now(void);
|
||||
void mp_bluetooth_hci_poll_in_ms(uint32_t ms);
|
||||
|
||||
// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
|
||||
// Request new data from the uart and pass to the stack, and run pending events/callouts.
|
||||
// This is a low-level function and should not be called directly, use
|
||||
// mp_bluetooth_hci_poll_now/mp_bluetooth_hci_poll_in_ms instead.
|
||||
void mp_bluetooth_hci_poll(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Damien P. George
|
||||
* Copyright (c) 2020-2021 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -31,30 +31,79 @@
|
||||
#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
|
||||
|
||||
#include "lib/btstack/src/btstack.h"
|
||||
#include "lib/btstack/platform/embedded/btstack_run_loop_embedded.h"
|
||||
#include "lib/btstack/platform/embedded/hal_cpu.h"
|
||||
#include "lib/btstack/platform/embedded/hal_time_ms.h"
|
||||
|
||||
#include "extmod/mpbthci.h"
|
||||
#include "extmod/btstack/btstack_hci_uart.h"
|
||||
#include "extmod/btstack/modbluetooth_btstack.h"
|
||||
#include "mpbthciport.h"
|
||||
|
||||
// The IRQ functionality in btstack_run_loop_embedded.c is not used, so the
|
||||
// following three functions are empty.
|
||||
void mp_bluetooth_hci_poll_in_ms(uint32_t ms);
|
||||
|
||||
void hal_cpu_disable_irqs(void) {
|
||||
static btstack_linked_list_t mp_btstack_runloop_timers;
|
||||
|
||||
static void mp_btstack_runloop_init(void) {
|
||||
mp_btstack_runloop_timers = NULL;
|
||||
}
|
||||
|
||||
void hal_cpu_enable_irqs(void) {
|
||||
static void mp_btstack_runloop_set_timer(btstack_timer_source_t *tim, uint32_t timeout_ms) {
|
||||
tim->timeout = mp_hal_ticks_ms() + timeout_ms + 1;
|
||||
}
|
||||
|
||||
void hal_cpu_enable_irqs_and_sleep(void) {
|
||||
static void mp_btstack_runloop_add_timer(btstack_timer_source_t *tim) {
|
||||
btstack_linked_item_t **node = &mp_btstack_runloop_timers;
|
||||
for (; *node; node = &(*node)->next) {
|
||||
btstack_timer_source_t *node_tim = (btstack_timer_source_t *)*node;
|
||||
if (node_tim == tim) {
|
||||
// Timer is already in the list, don't add it.
|
||||
return;
|
||||
}
|
||||
int32_t delta = btstack_time_delta(tim->timeout, node_tim->timeout);
|
||||
if (delta < 0) {
|
||||
// Found sorted location in list.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert timer into list in sorted location.
|
||||
tim->item.next = *node;
|
||||
*node = &tim->item;
|
||||
|
||||
// Reschedule the HCI poll if this timer is at the head of the list.
|
||||
if (mp_btstack_runloop_timers == &tim->item) {
|
||||
int32_t delta_ms = btstack_time_delta(tim->timeout, mp_hal_ticks_ms());
|
||||
mp_bluetooth_hci_poll_in_ms(delta_ms);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t hal_time_ms(void) {
|
||||
static bool mp_btstack_runloop_remove_timer(btstack_timer_source_t *tim) {
|
||||
return btstack_linked_list_remove(&mp_btstack_runloop_timers, (btstack_linked_item_t *)tim);
|
||||
}
|
||||
|
||||
static void mp_btstack_runloop_execute(void) {
|
||||
// Should not be called.
|
||||
}
|
||||
|
||||
static void mp_btstack_runloop_dump_timer(void) {
|
||||
// Not implemented/needed.
|
||||
}
|
||||
|
||||
static uint32_t mp_btstack_runloop_get_time_ms(void) {
|
||||
return mp_hal_ticks_ms();
|
||||
}
|
||||
|
||||
static const btstack_run_loop_t mp_btstack_runloop_stm32 = {
|
||||
&mp_btstack_runloop_init,
|
||||
NULL, // add_data_source,
|
||||
NULL, // remove_data_source,
|
||||
NULL, // enable_data_source_callbacks,
|
||||
NULL, // disable_data_source_callbacks,
|
||||
&mp_btstack_runloop_set_timer,
|
||||
&mp_btstack_runloop_add_timer,
|
||||
&mp_btstack_runloop_remove_timer,
|
||||
&mp_btstack_runloop_execute,
|
||||
&mp_btstack_runloop_dump_timer,
|
||||
&mp_btstack_runloop_get_time_ms,
|
||||
};
|
||||
|
||||
STATIC const hci_transport_config_uart_t hci_transport_config_uart = {
|
||||
HCI_TRANSPORT_CONFIG_UART,
|
||||
MICROPY_HW_BLE_UART_BAUDRATE,
|
||||
@ -68,22 +117,32 @@ void mp_bluetooth_hci_poll(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process uart data.
|
||||
// Process UART data.
|
||||
if (mp_bluetooth_btstack_state != MP_BLUETOOTH_BTSTACK_STATE_HALTING) {
|
||||
mp_bluetooth_btstack_hci_uart_process();
|
||||
}
|
||||
|
||||
// Call the BTstack run loop.
|
||||
btstack_run_loop_embedded_execute_once();
|
||||
// Process any BTstack timers.
|
||||
while (mp_btstack_runloop_timers != NULL) {
|
||||
btstack_timer_source_t *tim = (btstack_timer_source_t *)mp_btstack_runloop_timers;
|
||||
int32_t delta_ms = btstack_time_delta(tim->timeout, mp_hal_ticks_ms());
|
||||
if (delta_ms > 0) {
|
||||
// Timer has not expired yet, reschedule HCI poll for this timer.
|
||||
mp_bluetooth_hci_poll_in_ms(delta_ms);
|
||||
break;
|
||||
}
|
||||
btstack_linked_list_pop(&mp_btstack_runloop_timers);
|
||||
tim->process(tim);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_bluetooth_btstack_port_init(void) {
|
||||
static bool run_loop_init = false;
|
||||
if (!run_loop_init) {
|
||||
run_loop_init = true;
|
||||
btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
|
||||
btstack_run_loop_init(&mp_btstack_runloop_stm32);
|
||||
} else {
|
||||
btstack_run_loop_embedded_get_instance()->init();
|
||||
mp_btstack_runloop_stm32.init();
|
||||
}
|
||||
|
||||
// hci_dump_open(NULL, HCI_DUMP_STDOUT);
|
||||
|
||||
@ -432,6 +432,9 @@ struct _mp_bluetooth_btstack_root_pointers_t;
|
||||
/* pointers to all CAN objects (if they have been created) */ \
|
||||
struct _pyb_can_obj_t *pyb_can_obj_all[MICROPY_HW_MAX_CAN]; \
|
||||
\
|
||||
/* USB_VCP IRQ callbacks (if they have been set) */ \
|
||||
mp_obj_t pyb_usb_vcp_irq[MICROPY_HW_USB_CDC_NUM]; \
|
||||
\
|
||||
/* list of registered NICs */ \
|
||||
mp_obj_list_t mod_network_nic_list; \
|
||||
\
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
#include "extmod/modbluetooth.h"
|
||||
#include "extmod/nimble/modbluetooth_nimble.h"
|
||||
#include "extmod/nimble/hal/hal_uart.h"
|
||||
#include "mpbthciport.h"
|
||||
|
||||
// Get any pending data from the UART and send it to NimBLE's HCI buffers.
|
||||
// Any further processing by NimBLE will be run via its event queue.
|
||||
@ -56,6 +57,12 @@ void mp_bluetooth_hci_poll(void) {
|
||||
// Run any remaining events (e.g. if there was no UART data).
|
||||
mp_bluetooth_nimble_os_eventq_run_all();
|
||||
}
|
||||
|
||||
if (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
|
||||
// Call this function again in 128ms to check for new events.
|
||||
// TODO: improve this by only calling back when needed.
|
||||
mp_bluetooth_hci_poll_in_ms(128);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Port-specific helpers for the generic NimBLE bindings. -----------------
|
||||
|
||||
@ -134,6 +134,10 @@ STATIC mp_obj_t network_lan_config(size_t n_args, const mp_obj_t *args, mp_map_t
|
||||
eth_set_trace(self->eth, mp_obj_get_int(e->value));
|
||||
break;
|
||||
}
|
||||
case MP_QSTR_low_power: {
|
||||
eth_low_power_mode(self->eth, mp_obj_get_int(e->value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
|
||||
}
|
||||
|
||||
@ -60,10 +60,10 @@ void pendsv_init(void) {
|
||||
// the given exception object using nlr_jump in the context of the top-level
|
||||
// thread.
|
||||
void pendsv_kbd_intr(void) {
|
||||
if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_NULL) {
|
||||
if (MP_STATE_MAIN_THREAD(mp_pending_exception) == MP_OBJ_NULL) {
|
||||
mp_sched_keyboard_interrupt();
|
||||
} else {
|
||||
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
|
||||
MP_STATE_MAIN_THREAD(mp_pending_exception) = MP_OBJ_NULL;
|
||||
pendsv_object = &MP_STATE_VM(mp_kbd_exception);
|
||||
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/modbluetooth.h"
|
||||
#include "mpbthciport.h"
|
||||
#include "rtc.h"
|
||||
#include "rfcore.h"
|
||||
|
||||
@ -714,8 +715,7 @@ void IPCC_C1_RX_IRQHandler(void) {
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH
|
||||
// Queue up the scheduler to process UART data and run events.
|
||||
extern void mp_bluetooth_hci_systick(uint32_t ticks_ms);
|
||||
mp_bluetooth_hci_systick(0);
|
||||
mp_bluetooth_hci_poll_now();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -276,6 +276,13 @@ void sdram_leave_low_power(void) {
|
||||
(0 << 9U)); // Mode Register Definition
|
||||
}
|
||||
|
||||
#if __GNUC__ >= 11
|
||||
// Prevent array bounds warnings when accessing SDRAM_START_ADDRESS as a memory pointer.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||
#endif
|
||||
|
||||
bool sdram_test(bool fast) {
|
||||
uint8_t const pattern = 0xaa;
|
||||
uint8_t const antipattern = 0x55;
|
||||
@ -325,4 +332,8 @@ bool sdram_test(bool fast) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if __GNUC__ >= 11
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // FMC_SDRAM_BANK
|
||||
|
||||
@ -122,6 +122,7 @@ void soft_timer_gc_mark_all(void) {
|
||||
}
|
||||
|
||||
void soft_timer_static_init(soft_timer_entry_t *entry, uint16_t mode, uint32_t delta_ms, void (*cb)(soft_timer_entry_t *)) {
|
||||
mp_pairheap_init_node(soft_timer_lt, &entry->pairheap);
|
||||
entry->flags = 0;
|
||||
entry->mode = mode;
|
||||
entry->delta_ms = delta_ms;
|
||||
|
||||
@ -56,4 +56,11 @@ void soft_timer_static_init(soft_timer_entry_t *entry, uint16_t mode, uint32_t d
|
||||
void soft_timer_insert(soft_timer_entry_t *entry, uint32_t initial_delta_ms);
|
||||
void soft_timer_remove(soft_timer_entry_t *entry);
|
||||
|
||||
// The timer will be reinserted into the heap so that it is called after initial_delta_ms milliseconds.
|
||||
// After that, if it's periodic, it will continue to be called every entry->delta_ms milliseconds.
|
||||
static inline void soft_timer_reinsert(soft_timer_entry_t *entry, uint32_t initial_delta_ms) {
|
||||
soft_timer_remove(entry);
|
||||
soft_timer_insert(entry, initial_delta_ms);
|
||||
}
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_SOFTTIMER_H
|
||||
|
||||
@ -37,9 +37,6 @@ enum {
|
||||
#if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
|
||||
SYSTICK_DISPATCH_LWIP,
|
||||
#endif
|
||||
#if MICROPY_PY_BLUETOOTH
|
||||
SYSTICK_DISPATCH_BLUETOOTH_HCI,
|
||||
#endif
|
||||
SYSTICK_DISPATCH_MAX
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user