Create first BLE-only board, Micro:Bit v2

This fixes build issues with USB off, tweaks the README to allow
for BLE-only boards and adds the Micro:Bit v2 definition.

Fixes #4546
This commit is contained in:
Scott Shawcroft 2021-07-08 19:11:05 -07:00
parent 9fdecacec7
commit 0fadf028ef
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
34 changed files with 412 additions and 566 deletions

View File

@ -303,6 +303,7 @@ jobs:
- "metro_m4_express"
- "metro_m7_1011"
- "metro_nrf52840_express"
- "microbit_v2"
- "mini_sam_m4"
- "monster_m4sk"
- "ndgarage_ndbit6"

View File

@ -14,25 +14,30 @@ CircuitPython
computers called microcontrollers. Microcontrollers are the brains of many electronics including a
wide variety of development boards used to build hobby projects and prototypes. CircuitPython in
electronics is one of the best ways to learn to code because it connects code to reality. Simply
install CircuitPython on a supported board via drag and drop and then edit a ``code.py`` file on
the CIRCUITPY drive. The code will automatically reload. No software installs are needed besides a
text editor (we recommend `Mu <https://codewith.mu/>`_ for beginners.)
install CircuitPython on a supported USB board usually via drag and drop and then edit a ``code.py``
file on the CIRCUITPY drive. The code will automatically reload. No software installs are needed
besides a text editor (we recommend `Mu <https://codewith.mu/>`_ for beginners.)
CircuitPython features unified Python core APIs and a growing list of 150+ device libraries and
Starting with CircuitPython 7.0.0, some boards may only be connectable over Bluetooth Low Energy
(BLE). Those boards provide serial and file access over BLE instead of USB using open protocols.
(Some boards may use both USB and BLE.) BLE access can be done from a variety of apps including
`code.circuitpythonn.org <https://code.circuitpython.org>`_.
CircuitPython features unified Python core APIs and a growing list of 300+ device libraries and
drivers that work with it. These libraries also work on single board computers with regular
Python via the `Adafruit Blinka Library <https://github.com/adafruit/Adafruit_Blinka>`_.
CircuitPython is based on `MicroPython <https://micropython.org>`_. See
`below <#differences-from-micropython>`_ for differences. CircuitPython development is sponsored by
`Adafruit <https://adafruit.com>`_ and is available on their educational development boards. Please
support both MicroPython and Adafruit.
`below <#differences-from-micropython>`_ for differences. Most, but not all, CircuitPython
development is sponsored by `Adafruit <https://adafruit.com>`_ and is available on their educational
development boards. Please support both MicroPython and Adafruit.
Get CircuitPython
------------------
Official binaries for all supported boards are available through
`circuitpython.org/downloads <https://circuitpython.org/downloads>`_. The site includes stable, unstable and
continuous builds. Full release notes and assets are available through
continuous builds. Full release notes are available through
`GitHub releases <https://github.com/adafruit/circuitpython/releases>`_ as well.
Documentation
@ -85,7 +90,9 @@ If you'd like to use the term "CircuitPython" and Blinka for your product here i
* Your product is listed on `circuitpython.org <https://circuitpython.org>`__ (source
`here <https://github.com/adafruit/circuitpython-org/>`_). This is to ensure that a user of your
product can always download the latest version of CircuitPython from the standard place.
* Your product has a user accessible USB plug which appears as a CIRCUITPY drive when plugged in.
* Your product has a user accessible USB plug which appears as a CIRCUITPY drive when plugged in
AND/OR provides file and serial access over Bluetooth Low Energy. Boards that do not support USB
should be clearly marked as BLE-only CircuitPython.
If you choose not to meet these requirements, then we ask you call your version of CircuitPython
something else (for example, SuperDuperPython) and not use the Blinka logo. You can say it is
@ -98,10 +105,11 @@ Differences from `MicroPython <https://github.com/micropython/micropython>`__
CircuitPython:
- Supports native USB on all boards, allowing file editing without special tools.
- Supports native USB on most boards and BLE otherwise, allowing file editing without special tools.
- Floats (aka decimals) are enabled for all builds.
- Error messages are translated into 10+ languages.
- Does not support concurrency within Python (including interrupts and threading). Some concurrency
- Concurrenncy within Python is not well supported. Interrupts and threading are disabled.
async/await keywords are available on some boards for cooperative multitasking. Some concurrency
is achieved with native modules for tasks that require it such as audio file playback.
Behavior
@ -110,23 +118,23 @@ Behavior
- The order that files are run and the state that is shared between
them. CircuitPython's goal is to clarify the role of each file and
make each file independent from each other.
- ``boot.py`` (or ``settings.py``) runs only once on start up before
USB is initialized. This lays the ground work for configuring USB at
startup rather than it being fixed. Since serial is not available,
output is written to ``boot_out.txt``.
- ``code.py`` (or ``main.py``) is run after every reload until it
finishes or is interrupted. After it is done running, the vm and
hardware is reinitialized. **This means you cannot read state from**
``code.py`` **in the REPL anymore, as the REPL is a fresh vm.** CircuitPython's goal for this
change includes reducing confusion about pins and memory being used.
- After the main code is finished the REPL can be entered by pressing any key.
- Autoreload state will be maintained across reload.
- Adds a safe mode that does not run user code after a hard crash or
brown out. The hope is that this will make it easier to fix code that
causes nasty crashes by making it available through mass storage
after the crash. A reset (the button) is needed after it's fixed to
get back into normal mode.
- RGB status LED indicating CircuitPython state, and errors through a sequence of colored flashes.
- ``boot.py`` (or ``settings.py``) runs only once on start up before
USB is initialized. This lays the ground work for configuring USB at
startup rather than it being fixed. Since serial is not available,
output is written to ``boot_out.txt``.
- ``code.py`` (or ``main.py``) is run after every reload until it
finishes or is interrupted. After it is done running, the vm and
hardware is reinitialized. **This means you cannot read state from**
``code.py`` **in the REPL anymore, as the REPL is a fresh vm.** CircuitPython's goal for this
change includes reducing confusion about pins and memory being used.
- After the main code is finished the REPL can be entered by pressing any key.
- Autoreload state will be maintained across reload.
- Adds a safe mode that does not run user code after a hard crash or brown out. This makes it
possible to fix code that causes nasty crashes by making it available through mass storage after
the crash. A reset (the button) is needed after it's fixed to get back into normal mode.
- RGB status LED indicating CircuitPython state.
- Re-runs ``code.py`` or other main file after file system writes over USB mass storage. (Disable with
``supervisor.disable_autoreload()``)
- Autoreload is disabled while the REPL is active.
@ -140,7 +148,7 @@ API
- Unified hardware APIs. Documented on
`ReadTheDocs <https://circuitpython.readthedocs.io/en/latest/shared-bindings/index.html>`_.
- API docs are rST within the C files in ``shared-bindings``.
- API docs are Python stubs within the C files in ``shared-bindings``.
- No ``machine`` API.
Modules

20
main.c
View File

@ -348,6 +348,14 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
#endif
}
// Print done before resetting everything so that we get the message over
// BLE before it is reset and we have a delay before reconnect.
if (reload_requested && result.return_code == PYEXEC_EXCEPTION) {
serial_write_compressed(translate("\nCode stopped by auto-reload.\n"));
} else {
serial_write_compressed(translate("\nCode done running.\n"));
}
// Finished executing python code. Cleanup includes a board reset.
cleanup_after_vm(heap);
@ -361,15 +369,13 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
if (reload_requested) {
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
}
else if (result.return_code == 0) {
} else if (result.return_code == 0) {
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS;
if (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS) {
skip_repl = true;
skip_wait = true;
}
}
else {
} else {
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_ERROR;
// Deep sleep cannot be skipped
// TODO: settings in deep sleep should persist, using a new sleep memory API
@ -383,12 +389,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
skip_repl = reload_requested;
skip_wait = true;
}
if (reload_requested && result.return_code == PYEXEC_EXCEPTION) {
serial_write_compressed(translate("\nCode stopped by auto-reload.\n"));
} else {
serial_write_compressed(translate("\nCode done running.\n"));
}
}
// Program has finished running.

View File

@ -96,7 +96,6 @@ endif
ifeq ($(NRF_DEBUG_PRINT), 1)
CFLAGS += -DNRF_DEBUG_PRINT=1
SRC_SUPERVISOR += supervisor/debug_uart.c
endif
# option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk
@ -248,7 +247,7 @@ SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_MOD) $(SRC_COMMON_HAL_EXPANDED) $(S
SRC_QSTR_PREPROCESSOR +=
all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2
all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 $(BUILD)/firmware.combined.hex
$(BUILD)/firmware.elf: $(OBJ) $(GENERATED_LD_FILE)
$(STEPECHO) "LINK $@"
@ -266,6 +265,10 @@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf
$(Q)$(OBJCOPY) -O ihex $^ $@
# $(Q)$(OBJCOPY) -O ihex -j .vectors -j .text -j .data $^ $@
$(BUILD)/firmware.combined.hex: $(BUILD)/firmware.hex $(SOFTDEV_HEX)
$(STEPECHO) "Create $@"
$(Q)hexmerge.py -o $@ $^
$(BUILD)/firmware.uf2: $(BUILD)/firmware.hex
$(ECHO) "Create $@"
$(PYTHON3) $(TOP)/tools/uf2/utils/uf2conv.py -f 0xADA52840 -c -o "$(BUILD)/firmware.uf2" $^

View File

@ -38,6 +38,10 @@
#include "py/misc.h"
#include "py/mpstate.h"
#if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE
#include "supervisor/shared/bluetooth/serial.h"
#endif
nrf_nvic_state_t nrf_nvic_state = { 0 };
// Flag indicating progress of internal flash operation.
@ -132,6 +136,9 @@ void SD_EVT_IRQHandler(void) {
}
}
#if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE
ble_serial_disable();
#endif
while (1) {
uint16_t evt_len = sizeof(m_ble_evt_buf);
const uint32_t err_code = sd_ble_evt_get(m_ble_evt_buf, &evt_len);
@ -173,4 +180,7 @@ void SD_EVT_IRQHandler(void) {
}
#endif
}
#if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE
ble_serial_enable();
#endif
}

View File

@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
* Copyright (c) 2021 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,36 +24,15 @@
* THE SOFTWARE.
*/
#include "supervisor/serial.h"
#include "supervisor/workflow.h"
void serial_early_init(void) {
#include "supervisor/board.h"
void board_init(void) {
}
void serial_init(void) {
}
bool serial_connected(void) {
bool board_requests_safe_mode(void) {
return false;
}
char serial_read(void) {
return 0;
}
void reset_board(void) {
bool serial_bytes_available(void) {
return false;
}
void serial_write(const char *text) {
(void)text;
}
void supervisor_workflow_reset(void) {
}
bool supervisor_workflow_active(void) {
return false;
}

View File

@ -0,0 +1,56 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Glenn Ruben Bakke
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
*
* 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 "nrfx/hal/nrf_gpio.h"
#define MICROPY_HW_BOARD_NAME "micro:bit v2"
#define MICROPY_HW_MCU_NAME "nRF52833"
#define CIRCUITPY_INTERNAL_NVM_SIZE 0
#define CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE (60 * 1024)
#define CIRCUITPY_BLE_CONFIG_SIZE (12 * 1024)
// The RUN_MIC pin
#define MICROPY_HW_LED_STATUS (&pin_P0_20)
// Reduce nRF SoftRadio memory usage
#define BLEIO_VS_UUID_COUNT 10
#define BLEIO_HVN_TX_QUEUE_SIZE 2
#define BLEIO_CENTRAL_ROLE_COUNT 2
#define BLEIO_PERIPH_ROLE_COUNT 2
#define BLEIO_TOTAL_CONNECTION_COUNT 2
#define BLEIO_ATTR_TAB_SIZE (BLE_GATTS_ATTR_TAB_SIZE_DEFAULT * 2)
#define SOFTDEVICE_RAM_SIZE (32 * 1024)
#define BOOTLOADER_SIZE (0)
#define BOOTLOADER_SETTING_SIZE (0)
#define BOARD_HAS_32KHZ_XTAL (0)
#define DEBUG_UART_TX (&pin_P0_06)
#define DEBUG_UART_RX (&pin_P1_08)

View File

@ -0,0 +1,36 @@
CIRCUITPY_CREATOR_ID = 0x239A
CIRCUITPY_CREATION_ID = 0x80D8
MCU_CHIP = nrf52833
INTERNAL_FLASH_FILESYSTEM = 1
CIRCUITPY_ALARM = 0
CIRCUITPY_AUDIOMP3 = 0
CIRCUITPY_BINASCII = 0
CIRCUITPY_BITBANGIO = 0
CIRCUITPY_BUILTINS_POW3=0
CIRCUITPY_BUSDEVICE = 0
CIRCUITPY_COUNTIO = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_JSON = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_MSGPACK = 0
CIRCUITPY_NEOPIXEL_WRITE = 0
CIRCUITPY_NVM = 0
CIRCUITPY_PIXELBUF = 0
CIRCUITPY_RE = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_SDCARDIO = 0
CIRCUITPY_ULAB = 0
CIRCUITPY_USB = 0
MICROPY_PY_ASYNC_AWAIT = 0
# Override optimization to keep binary small
OPTIMIZATION_FLAGS = -Os
SUPEROPT_VM = 0
SUPEROPT_GC = 0

View File

@ -0,0 +1,59 @@
#include "shared-bindings/board/__init__.h"
STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_P0), MP_ROM_PTR(&pin_P0_02) }, // RING0
{ MP_ROM_QSTR(MP_QSTR_P1), MP_ROM_PTR(&pin_P0_03) }, // RING1
{ MP_ROM_QSTR(MP_QSTR_P2), MP_ROM_PTR(&pin_P0_04) }, // RING2
{ MP_ROM_QSTR(MP_QSTR_P3), MP_ROM_PTR(&pin_P0_31) }, // COLR3
{ MP_ROM_QSTR(MP_QSTR_P4), MP_ROM_PTR(&pin_P0_28) }, // COLR1
{ MP_ROM_QSTR(MP_QSTR_BTN_A), MP_ROM_PTR(&pin_P0_14) },
{ MP_ROM_QSTR(MP_QSTR_P5), MP_ROM_PTR(&pin_P0_14) }, // BTN A
{ MP_ROM_QSTR(MP_QSTR_P6), MP_ROM_PTR(&pin_P1_05) }, // COLR4
{ MP_ROM_QSTR(MP_QSTR_P7), MP_ROM_PTR(&pin_P0_11) }, // COLR2
{ MP_ROM_QSTR(MP_QSTR_P8), MP_ROM_PTR(&pin_P0_10) }, // GPIO1
{ MP_ROM_QSTR(MP_QSTR_P9), MP_ROM_PTR(&pin_P0_09) }, // GPIO2
{ MP_ROM_QSTR(MP_QSTR_P10), MP_ROM_PTR(&pin_P0_30) }, // COLR5
{ MP_ROM_QSTR(MP_QSTR_BTN_B), MP_ROM_PTR(&pin_P0_23) },
{ MP_ROM_QSTR(MP_QSTR_P11), MP_ROM_PTR(&pin_P0_23) }, // BTN B
{ MP_ROM_QSTR(MP_QSTR_P12), MP_ROM_PTR(&pin_P0_12) }, // GPIO4
{ MP_ROM_QSTR(MP_QSTR_P13), MP_ROM_PTR(&pin_P0_17) }, // SPI_EXT_SCK
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_17) }, // SPI_EXT_SCK
{ MP_ROM_QSTR(MP_QSTR_P14), MP_ROM_PTR(&pin_P0_01) }, // SPI_EXT_MISO
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_01) }, // SPI_EXT_MISO
{ MP_ROM_QSTR(MP_QSTR_P15), MP_ROM_PTR(&pin_P0_13) }, // SPI_EXT_MOSI
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_13) }, // SPI_EXT_MOSI
{ MP_ROM_QSTR(MP_QSTR_P16), MP_ROM_PTR(&pin_P0_05) }, // GPIO3
{ MP_ROM_QSTR(MP_QSTR_P19), MP_ROM_PTR(&pin_P0_08) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_08) },
{ MP_ROM_QSTR(MP_QSTR_P20), MP_ROM_PTR(&pin_P0_16) },
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_16) },
// Internal I2C
{ MP_ROM_QSTR(MP_QSTR_INTERNAL_SCL), MP_ROM_PTR(&pin_P0_26) },
{ MP_ROM_QSTR(MP_QSTR_INTERNAL_SDA), MP_ROM_PTR(&pin_P1_00) },
{ MP_ROM_QSTR(MP_QSTR_INTERNAL_INTERRUPT), MP_ROM_PTR(&pin_P0_25) },
{ MP_ROM_QSTR(MP_QSTR_MICROPHONE_ENABLE), MP_ROM_PTR(&pin_P0_20) },
{ MP_ROM_QSTR(MP_QSTR_MICROPHONE), MP_ROM_PTR(&pin_P0_05) },
{ MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_P0_00) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_06) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P1_08) },
{ MP_ROM_QSTR(MP_QSTR_LOGO), MP_ROM_PTR(&pin_P1_04) },
{ MP_ROM_QSTR(MP_QSTR_COL1), MP_ROM_PTR(&pin_P0_28) },
{ MP_ROM_QSTR(MP_QSTR_COL2), MP_ROM_PTR(&pin_P0_11) },
{ MP_ROM_QSTR(MP_QSTR_COL3), MP_ROM_PTR(&pin_P0_31) },
{ MP_ROM_QSTR(MP_QSTR_COL4), MP_ROM_PTR(&pin_P1_05) },
{ MP_ROM_QSTR(MP_QSTR_COL5), MP_ROM_PTR(&pin_P0_30) },
{ MP_ROM_QSTR(MP_QSTR_ROW1), MP_ROM_PTR(&pin_P0_21) },
{ MP_ROM_QSTR(MP_QSTR_ROW2), MP_ROM_PTR(&pin_P0_22) },
{ MP_ROM_QSTR(MP_QSTR_ROW3), MP_ROM_PTR(&pin_P0_15) },
{ MP_ROM_QSTR(MP_QSTR_ROW4), MP_ROM_PTR(&pin_P0_24) },
{ MP_ROM_QSTR(MP_QSTR_ROW5), MP_ROM_PTR(&pin_P0_19) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

View File

@ -965,11 +965,22 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) {
adapter->connection_objs = NULL;
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
bleio_connection_internal_t *connection = &bleio_connections[i];
// Disconnect all connections with Python state cleanly. Keep any supervisor-only connections.
if (connection->connection_obj != mp_const_none &&
connection->conn_handle != BLE_CONN_HANDLE_INVALID) {
// Disconnect all connections cleanly.
if (connection->conn_handle != BLE_CONN_HANDLE_INVALID) {
common_hal_bleio_connection_disconnect(connection);
}
connection->connection_obj = mp_const_none;
}
// Wait up to 125 ms (128 ticks) for disconnect to complete. This should be
// greater than most connection intervals.
bool any_connected = false;
uint64_t start_ticks = supervisor_ticks_ms64();
while (any_connected && supervisor_ticks_ms64() - start_ticks < 128) {
any_connected = false;
for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) {
bleio_connection_internal_t *connection = &bleio_connections[i];
any_connected |= connection->conn_handle != BLE_CONN_HANDLE_INVALID;
}
}
}

View File

@ -40,6 +40,8 @@
#include "shared-bindings/_bleio/PacketBuffer.h"
#include "supervisor/shared/tick.h"
#include "supervisor/shared/bluetooth/serial.h"
STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, uint8_t *data, uint16_t len) {
if (len + sizeof(uint16_t) > ringbuf_capacity(&self->ringbuf)) {
// This shouldn't happen but can if our buffer size was much smaller than
@ -482,8 +484,8 @@ mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length(bleio_packet_
}
void common_hal_bleio_packet_buffer_flush(bleio_packet_buffer_obj_t *self) {
while (self->pending_size != 0 &&
self->packet_queued &&
while ((self->pending_size != 0 ||
self->packet_queued) &&
self->conn_handle != BLE_CONN_HANDLE_INVALID &&
!mp_hal_is_interrupted()) {
RUN_BACKGROUND_TASKS;

View File

@ -102,6 +102,7 @@ void bleio_reset() {
return;
}
supervisor_stop_bluetooth();
bleio_adapter_reset(&common_hal_bleio_adapter_obj);
common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false);
bonding_reset();

View File

@ -30,11 +30,6 @@
#include "common-hal/alarm/SleepMemory.h"
#include "nrf_power.h"
#ifdef NRF_DEBUG_PRINT
extern void dbg_dump_RAMreg(void);
#include "supervisor/serial.h" // dbg_printf()
#endif
__attribute__((section(".uninitialized"))) static uint8_t _sleepmem[SLEEP_MEMORY_LENGTH];
__attribute__((section(".uninitialized"))) uint8_t sleepmem_wakeup_event;
__attribute__((section(".uninitialized"))) uint8_t sleepmem_wakeup_pin;
@ -81,9 +76,6 @@ static void initialize_sleep_memory(void) {
sleepmem_wakeup_pin = 0;
set_memory_retention();
#ifdef NRF_DEBUG_PRINT
// dbg_dump_RAMreg();
#endif
_sleepmem_magicnum = SLEEP_MEMORY_DATA_GUARD;
}
@ -92,7 +84,7 @@ void alarm_sleep_memory_reset(void) {
if (!is_sleep_memory_valid()) {
initialize_sleep_memory();
#ifdef NRF_DEBUG_PRINT
dbg_printf("sleep memory initialized\r\n");
mp_printf(&mp_plat_print, "sleep memory initialized\r\n");
#endif
}
}

View File

@ -42,10 +42,6 @@
#include "supervisor/port.h"
#include "supervisor/serial.h" // serial_connected()
#ifdef NRF_DEBUG_PRINT
#include "supervisor/serial.h" // dbg_printf()
extern int dbg_check_RTCprescaler(void);
#endif
#include "supervisor/qspi_flash.h"
#include "nrf.h"
@ -102,7 +98,7 @@ static const char *cause_str[] = {
};
void print_wakeup_cause(nrf_sleep_source_t cause) {
if (cause >= 0 && cause < NRF_SLEEP_WAKEUP_ZZZ) {
dbg_printf("wakeup cause = NRF_SLEEP_WAKEUP_%s\r\n",
mp_printf(&mp_plat_print, "wakeup cause = NRF_SLEEP_WAKEUP_%s\r\n",
cause_str[(int)cause]);
}
}
@ -223,7 +219,7 @@ void system_on_idle_until_alarm(int64_t timediff_ms, uint32_t prescaler) {
port_idle_until_interrupt();
#ifdef NRF_DEBUG_PRINT
if (ct > 0) {
dbg_printf("_");
mp_printf(&mp_plat_print, "_");
--ct;
}
#endif
@ -237,7 +233,7 @@ void system_on_idle_until_alarm(int64_t timediff_ms, uint32_t prescaler) {
}
}
#ifdef NRF_DEBUG_PRINT
dbg_printf("%c\r\n", reason);
mp_printf(&mp_plat_print, "%c\r\n", reason);
#endif
#if defined(MICROPY_QSPI_CS)
@ -252,7 +248,7 @@ void system_on_idle_until_alarm(int64_t timediff_ms, uint32_t prescaler) {
} else {
sec = (double)(tickdiff * prescaler) / 1024;
}
dbg_printf("lapse %6.1f sec\r\n", sec);
mp_printf(&mp_plat_print, "lapse %6.1f sec\r\n", sec);
#endif
}
@ -262,7 +258,7 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj
_setup_sleep_alarms(false, n_alarms, alarms);
#ifdef NRF_DEBUG_PRINT
dbg_printf("\r\nlight sleep...");
mp_printf(&mp_plat_print, "\r\nlight sleep...");
#endif
int64_t timediff_ms = alarm_time_timealarm_get_wakeup_timediff_ms();
@ -305,17 +301,14 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
alarm_time_timealarm_prepare_for_deep_sleep();
#ifdef NRF_DEBUG_PRINT
dbg_printf("\r\ndeep sleep...");
mp_printf(&mp_plat_print, "\r\ndeep sleep...");
#endif
int64_t timediff_ms = alarm_time_timealarm_get_wakeup_timediff_ms();
tick_set_prescaler(PRESCALER_VALUE_IN_DEEP_SLEEP - 1);
#ifdef NRF_DEBUG_PRINT
dbg_check_RTCprescaler(); // XXX
#endif
system_on_idle_until_alarm(timediff_ms, PRESCALER_VALUE_IN_DEEP_SLEEP);
#ifdef NRF_DEBUG_PRINT
dbg_printf("RESET...\r\n\r\n");
mp_printf(&mp_plat_print, "RESET...\r\n\r\n");
#endif
reset_cpu();
@ -326,30 +319,12 @@ void NORETURN common_hal_alarm_enter_deep_sleep(void) {
}
}
// old version deep sleep code that was used in common_hal_alarm_enter_deep_sleep()
// for anyone who might want true System OFF sleep ..
#if 0
void OLD_go_system_off(void) {
sleepmem_wakeup_event = SLEEPMEM_WAKEUP_BY_NONE;
sleepmem_wakeup_pin = WAKEUP_PIN_UNDEF;
uint8_t sd_enabled;
sd_softdevice_is_enabled(&sd_enabled);
set_memory_retention();
dbg_printf("OLD go system off.. %d\r\n", sd_enabled);
if (sd_enabled) {
sd_power_system_off();
} else {
NRF_POWER->SYSTEMOFF = 1;
}
}
#endif
void common_hal_alarm_pretending_deep_sleep(void) {
alarm_pin_pinalarm_prepare_for_deep_sleep();
alarm_time_timealarm_prepare_for_deep_sleep();
#ifdef NRF_DEBUG_PRINT
dbg_printf("\r\npretending to deep sleep...");
mp_printf(&mp_plat_print, "\r\npretending to deep sleep...");
#endif
int64_t timediff_ms = alarm_time_timealarm_get_wakeup_timediff_ms();

View File

@ -41,14 +41,11 @@
#include "nrf_soc.h"
#include <string.h>
#include "supervisor/serial.h" // dbg_print
#define WPIN_UNUSED 0xFF
volatile char _pinhandler_gpiote_count;
static bool pins_configured = false;
extern uint32_t reset_reason_saved;
extern void dbg_dump_GPIOregs(void);
void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, const mcu_pin_obj_t *pin, bool value, bool edge, bool pull) {
if (edge) {
@ -205,7 +202,7 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob
alarm_pin_pinalarm_obj_t *alarm = MP_OBJ_TO_PTR(alarms[i]);
pin_number = alarm->pin->number;
// dbg_printf("alarm_pin_pinalarm_set_alarms(pin#=%d, val=%d, pull=%d)\r\n", pin_number, alarm->value, alarm->pull);
// mp_printf(&mp_plat_print, "alarm_pin_pinalarm_set_alarms(pin#=%d, val=%d, pull=%d)\r\n", pin_number, alarm->value, alarm->pull);
if (alarm->value) {
high_alarms |= 1ull << pin_number;
high_count++;
@ -227,7 +224,7 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob
pins_configured = false;
}
} else {
// dbg_printf("alarm_pin_pinalarm_set_alarms() no valid pins\r\n");
// mp_printf(&mp_plat_print, "alarm_pin_pinalarm_set_alarms() no valid pins\r\n");
}
}
@ -235,8 +232,5 @@ void alarm_pin_pinalarm_prepare_for_deep_sleep(void) {
if (!pins_configured) {
configure_pins_for_sleep();
pins_configured = true;
#ifdef NRF_DEBUG_PRINT
// dbg_dump_GPIOregs();
#endif
}
}

View File

@ -57,6 +57,8 @@ static nrfx_uarte_t nrfx_uartes[] = {
#endif
};
static bool never_reset[NRFX_UARTE0_ENABLED + NRFX_UARTE1_ENABLED];
static uint32_t get_nrf_baud(uint32_t baudrate) {
static const struct {
@ -132,10 +134,28 @@ static void uart_callback_irq(const nrfx_uarte_event_t *event, void *context) {
void uart_reset(void) {
for (size_t i = 0; i < MP_ARRAY_SIZE(nrfx_uartes); i++) {
if (never_reset[i]) {
continue;
}
nrfx_uarte_uninit(&nrfx_uartes[i]);
}
}
void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) {
// Don't never reset objects on the heap.
if (gc_alloc_possible() && gc_nbytes(self) > 0) {
return;
}
for (size_t i = 0; i < MP_ARRAY_SIZE(nrfx_uartes); i++) {
if (self->uarte == &nrfx_uartes[i]) {
never_reset[i] = true;
break;
}
}
never_reset_pin_number(self->tx_pin_number);
never_reset_pin_number(self->rx_pin_number);
}
void common_hal_busio_uart_construct(busio_uart_obj_t *self,
const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx,
const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts,
@ -186,7 +206,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
.pselrts = (rts == NULL) ? NRF_UARTE_PSEL_DISCONNECTED : rts->number,
.p_context = self,
.baudrate = get_nrf_baud(baudrate),
.interrupt_priority = 7,
.interrupt_priority = NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY,
.hal_cfg = {
.hwfc = hwfc ? NRF_UARTE_HWFC_ENABLED : NRF_UARTE_HWFC_DISABLED,
.parity = (parity == BUSIO_UART_PARITY_NONE) ? NRF_UARTE_PARITY_EXCLUDED : NRF_UARTE_PARITY_INCLUDED
@ -197,14 +217,22 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
// Init buffer for rx
if (rx != NULL) {
// Initially allocate the UART's buffer in the long-lived part of the
// heap. UARTs are generally long-lived objects, but the "make long-
// lived" machinery is incapable of moving internal pointers like
// self->buffer, so do it manually. (However, as long as internal
// pointers like this are NOT moved, allocating the buffer
// in the long-lived pool is not strictly necessary)
// (This is a macro.)
if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) {
self->allocated_ringbuf = true;
// Use the provided buffer when given.
if (receiver_buffer != NULL) {
self->ringbuf.buf = receiver_buffer;
self->ringbuf.size = receiver_buffer_size - 1;
self->ringbuf.iput = 0;
self->ringbuf.iget = 0;
self->allocated_ringbuf = false;
// Initially allocate the UART's buffer in the long-lived part of the
// heap. UARTs are generally long-lived objects, but the "make long-
// lived" machinery is incapable of moving internal pointers like
// self->buffer, so do it manually. (However, as long as internal
// pointers like this are NOT moved, allocating the buffer
// in the long-lived pool is not strictly necessary)
// (This is a macro.)
} else if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size, true)) {
nrfx_uarte_uninit(self->uarte);
mp_raise_msg(&mp_type_MemoryError, translate("Failed to allocate RX buffer"));
}
@ -258,7 +286,16 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
self->rx_pin_number = NO_PIN;
self->rts_pin_number = NO_PIN;
self->cts_pin_number = NO_PIN;
ringbuf_free(&self->ringbuf);
if (self->allocated_ringbuf) {
ringbuf_free(&self->ringbuf);
}
for (size_t i = 0; i < MP_ARRAY_SIZE(nrfx_uartes); i++) {
if (self->uarte == &nrfx_uartes[i]) {
never_reset[i] = false;
break;
}
}
}
}
@ -320,10 +357,19 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data,
// EasyDMA can only access SRAM
uint8_t *tx_buf = (uint8_t *)data;
if (!nrfx_is_in_ram(data)) {
// TODO: If this is not too big, we could allocate it on the stack.
tx_buf = (uint8_t *)gc_alloc(len, false, false);
// Allocate long strings on the heap.
if (len > 128 && gc_alloc_possible()) {
tx_buf = (uint8_t *)gc_alloc(len, false, false);
} else {
tx_buf = alloca(len);
}
memcpy(tx_buf, data, len);
}
// There is a small chance we're called recursively during debugging. In that case,
// a UART write might already be in progress so wait for it to complete.
while (nrfx_uarte_tx_in_progress(self->uarte)) {
RUN_BACKGROUND_TASKS;
}
(*errcode) = nrfx_uarte_tx(self->uarte, tx_buf, len);
_VERIFY_ERR(*errcode);
@ -334,7 +380,7 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data,
RUN_BACKGROUND_TASKS;
}
if (!nrfx_is_in_ram(data)) {
if (!nrfx_is_in_ram(data) && gc_alloc_possible() && gc_nbytes(tx_buf) > 0) {
gc_free(tx_buf);
}

View File

@ -44,6 +44,7 @@ typedef struct {
ringbuf_t ringbuf;
uint8_t rx_char; // EasyDMA buf
bool rx_paused; // set by irq if no space in rbuf
bool allocated_ringbuf;
uint8_t tx_pin_number;
uint8_t rx_pin_number;

View File

@ -76,6 +76,9 @@
#define NRFX_UARTE_ENABLED 1
#define NRFX_UARTE0_ENABLED 1
#define NRFX_UARTE1_ENABLED 1
// Higher priority than non-timing sensitive BLE so that we can log over UART
// from it.
#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY 3
// PWM
#define NRFX_PWM0_ENABLED 1

View File

@ -1,241 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 Jun2Sak
*
* 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 <stdarg.h>
#include <stdint.h>
#include <string.h>
#ifdef NRF_DEBUG_PRINT
#define DEBUG_UART_TXPIN 26
#define DEBUG_UART_RXPIN 15
#include "nrfx.h"
#include "nrf_uart.h"
#include "nrf_gpio.h"
#include "nrf_rtc.h"
#include "nrfx_uarte.h"
#include "nrfx_rtc.h"
#include "supervisor/serial.h" // dbg_printf()
#include "shared-bindings/microcontroller/Processor.h"
#include "common-hal/alarm/__init__.h"
extern const nrfx_rtc_t rtc_instance; // port.c
extern uint32_t reset_reason_saved;
const nrfx_uarte_t _dbg_uart_inst = NRFX_UARTE_INSTANCE(1);
static int _dbg_uart_initialized = 0;
#define DBG_PBUF_LEN 80
static char _dbg_pbuf[DBG_PBUF_LEN + 1];
void _debug_uart_uninit(void) {
nrf_gpio_cfg(DEBUG_UART_TXPIN,
NRF_GPIO_PIN_DIR_INPUT,
NRF_GPIO_PIN_INPUT_DISCONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
nrfx_uarte_uninit(&_dbg_uart_inst);
}
void _debug_uart_init(void) {
// if (_dbg_uart_initialized) return;
nrfx_uarte_config_t config = {
.pseltxd = DEBUG_UART_TXPIN,
.pselrxd = DEBUG_UART_RXPIN,
.pselcts = NRF_UARTE_PSEL_DISCONNECTED,
.pselrts = NRF_UARTE_PSEL_DISCONNECTED,
.p_context = NULL,
.baudrate = NRF_UART_BAUDRATE_115200,
.interrupt_priority = 7,
.hal_cfg = {
.hwfc = NRF_UARTE_HWFC_DISABLED,
.parity = NRF_UARTE_PARITY_EXCLUDED
}
};
nrfx_uarte_init(&_dbg_uart_inst, &config, NULL);
// drive config
nrf_gpio_cfg(config.pseltxd,
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_DISCONNECT,
NRF_GPIO_PIN_PULLUP, // orig=NOPULL
NRF_GPIO_PIN_H0H1, // orig=S0S1
NRF_GPIO_PIN_NOSENSE);
_dbg_uart_initialized = 1;
return;
}
void _debug_print_substr(const char *text, uint32_t length) {
char *data = (char *)text;
int siz;
while (length != 0) {
if (length <= DBG_PBUF_LEN) {
siz = length;
} else {
siz = DBG_PBUF_LEN;
}
memcpy(_dbg_pbuf, data, siz);
_dbg_pbuf[siz] = 0;
nrfx_uarte_tx(&_dbg_uart_inst, (uint8_t const *)_dbg_pbuf, siz);
data += siz;
length -= siz;
}
}
void _debug_uart_deinit(void) {
nrfx_uarte_uninit(&_dbg_uart_inst);
}
int dbg_printf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
void dbg_dump_RTCreg(void) {
dbg_printf("\r\nRTC2\r\n");
NRF_RTC_Type *r = rtc_instance.p_reg;
dbg_printf("PRESCALER=%08X, ", (int)r->PRESCALER);
dbg_printf("COUNTER=%08X ", (int)r->COUNTER);
dbg_printf("INTENSET=%08X ", (int)r->INTENSET);
dbg_printf("EVTENSET=%08X\r\n", (int)r->EVTENSET);
dbg_printf("EVENTS_COMPARE[0..3]=%X,%X,%X,%X ", (int)r->EVENTS_COMPARE[0], (int)r->EVENTS_COMPARE[1], (int)r->EVENTS_COMPARE[2], (int)r->EVENTS_COMPARE[3]);
dbg_printf("CC[0..3]=%08X,%08X,%08X,%08X\r\n", (int)r->CC[0], (int)r->CC[1], (int)r->CC[2], (int)r->CC[3]);
}
int dbg_check_RTCprescaler(void) {
NRF_RTC_Type *r = rtc_instance.p_reg;
if ((int)r->PRESCALER == 0) {
dbg_printf("****** PRESCALER == 0\r\n");
return -1;
}
return 0;
}
void dbg_dump_RAMreg(void) {
int i;
for (i = 0; i <= 8; ++i) {
dbg_printf(" RAM%d:%08X", i, (int)(NRF_POWER->RAM[i].POWER));
if (i == 4) {
dbg_printf("\r\n");
}
}
dbg_printf("\r\n");
}
void dbg_dump_GPIOregs(void) {
int i, port, col;
NRF_GPIO_Type *gpio[] = { NRF_P0, NRF_P1 };
const char cnf_pull_chr[] = "-D*U"; // pull down, pull up
const char cnf_sense_chr[] = "-?HL"; // sense high, sense low
for (port = 0, col = 0; port <= 1; ++port) {
for (i = 0; i < 32; ++i) {
uint32_t cnf = gpio[port]->PIN_CNF[i];
if (cnf != 0x0002) { // changed from default value
dbg_printf("[%d_%02d]:%c%c%c%d%c ", port, i,
(cnf & 1) ? 'O' : 'I', // output, input
(cnf & 2) ? 'd' : 'c', // disconnected, connected
cnf_pull_chr[(cnf >> 2) & 3],
(int)((cnf >> 8) & 7), // drive config 0-7
cnf_sense_chr[(cnf >> 16) & 3]);
if (++col >= 6) {
dbg_printf("\r\n");
col = 0;
}
}
}
}
if (col > 0) {
dbg_printf("\r\n");
}
dbg_printf("GPIOTE\r\n");
NRF_GPIOTE_Type const *reg = NRF_GPIOTE;
const char config_mode_chr[] = "-E-T"; // event, task
const char config_pol_chr[] = "-HLT"; // low-to-Hi, hi-to-Low, Toggle
const char config_outinit_chr[] = "01"; // initial value is 0 or 1
for (i = 0, col = 0; i < 8; ++i) {
uint32_t conf = reg->CONFIG[i];
if (conf != 0) { // changed from default value
dbg_printf("CONFIG[%d]:%d_%02d,%c%c%c ", i,
(int)((conf >> 13) & 1), (int)((conf >> 8) & 0x1F),
config_mode_chr[conf & 3],
config_pol_chr[(conf >> 16) & 3],
(conf & 3) == 3 ?
config_outinit_chr[(conf >> 20) & 1] : '-');
if (++col >= 4) {
dbg_printf("\r\n");
col = 0;
}
}
}
if (col > 0) {
dbg_printf("\r\n");
}
for (i = 0; i < 8; ++i) {
dbg_printf("EVENTS_IN[%d]:%X ", i, (int)(reg->EVENTS_IN[i]));
if ((i & 3) == 3) {
dbg_printf("\r\n");
}
}
dbg_printf("EVENTS_PORT:%X INTENSET:%08X\r\n",
(int)(reg->EVENTS_PORT), (int)(reg->INTENSET));
}
void dbg_dumpQSPIreg(void) {
uint32_t r;
dbg_printf("QSPI\r\n");
r = NRF_QSPI->IFCONFIG0;
dbg_printf("IFCONFIG0 READ=%ld write=%ld ADDR=%ld DPM=%ld PPSIZE=%ld\r\n",
r & 7, (r >> 3) & 7, (r >> 6) & 1, (r >> 7) & 1, (r >> 12) & 1);
r = NRF_QSPI->IFCONFIG1;
dbg_printf("IFCONFIG1 SCKDELAY=%ld SPIMODE=%ld SCKFREQ=%ld\r\n",
r & 0xFF, (r >> 25) & 1, (r >> 28) & 0xF);
r = NRF_QSPI->STATUS;
dbg_printf("STATUS DPM=%ld READY=%ld SREG=0x%02lX\r\n",
(r >> 2) & 1, (r >> 3) & 1, (r >> 24) & 0xFF);
r = NRF_QSPI->DPMDUR;
dbg_printf("DPMDUR ENTER=%ld EXIT=%ld\r\n", r & 0xFFFF, (r >> 16) & 0xFFFF);
}
void dbg_dump_reset_reason(void) {
int reset_reason = (int)common_hal_mcu_processor_get_reset_reason();
const char *rr_str[] = {
"POWER_ON", "BROWNOUT", "SOFTWARE", "DEEPSLEEPALARM",
"RESET_PIN", "WATCHDOG", "UNKNOWN"
};
dbg_printf("reset_reason=%s\r\n", rr_str[reset_reason]);
}
#else /*!NRF_DEBUG_PRINT*/
int dbg_printf(const char *fmt, ...) {
return 0;
}
#endif /*!NRF_DEBUG_PRINT*/

View File

@ -75,10 +75,6 @@ static void power_warning_handler(void) {
reset_into_safe_mode(BROWNOUT);
}
#ifdef NRF_DEBUG_PRINT
extern void _debug_uart_init(void);
#endif
uint32_t reset_reason_saved = 0;
const nrfx_rtc_t rtc_instance = NRFX_RTC_INSTANCE(2);
@ -258,10 +254,6 @@ void reset_port(void) {
#endif
reset_all_pins();
#ifdef NRF_DEBUG_PRINT
_debug_uart_init();
#endif
}
void reset_to_bootloader(void) {
@ -389,7 +381,11 @@ void port_idle_until_interrupt(void) {
// function (whether or not SD is enabled)
int nested = __get_PRIMASK();
__disable_irq();
if (!tud_task_event_ready()) {
bool ok = true;
#if CIRCUITPY_USB
ok = !tud_task_event_ready();
#endif
if (ok) {
__DSB();
__WFI();
}

View File

@ -37,9 +37,6 @@
#include "supervisor/shared/external_flash/common_commands.h"
#include "supervisor/shared/external_flash/qspi_flash.h"
#ifdef NRF_DEBUG_PRINT
#include "supervisor/serial.h" // dbg_printf()
#endif
#ifdef QSPI_FLASH_POWERDOWN
// Parameters for external QSPI Flash power-down
@ -57,12 +54,6 @@
static int sck_delay_saved = 0;
#endif
#ifdef NRF_DEBUG_PRINT
extern void dbg_dumpQSPIreg(void);
#else
#define dbg_dumpQSPIreg(...)
#endif
// When USB is disconnected, disable QSPI in sleep mode to save energy
void qspi_disable(void) {
// If VBUS is detected, no need to disable QSPI
@ -289,20 +280,18 @@ void qspi_flash_enter_sleep(void) {
// enabling IFCONFIG0.DPMENABLE here won't work.
// -> do it in spi_flash_init()
// NRF_QSPI->IFCONFIG0 |= QSPI_IFCONFIG0_DPMENABLE_Msk;
// dbg_dumpQSPIreg();
// enter deep power-down mode (DPM)
NRF_QSPI->IFCONFIG1 |= QSPI_IFCONFIG1_DPMEN_Msk;
NRFX_DELAY_US(WAIT_AFTER_DPM_ENTER);
if (!(NRF_QSPI->STATUS & QSPI_STATUS_DPM_Msk)) {
#ifdef NRF_DEBUG_PRINT
dbg_printf("qspi flash: DPM failed\r\n");
mp_printf(&mp_plat_print, "qspi flash: DPM failed\r\n");
#endif
}
#endif
qspi_disable();
// dbg_dumpQSPIreg();
}
void qspi_flash_exit_sleep(void) {
@ -316,7 +305,7 @@ void qspi_flash_exit_sleep(void) {
if (NRF_QSPI->STATUS & QSPI_STATUS_DPM_Msk) {
#ifdef NRF_DEBUG_PRINT
dbg_printf("qspi flash: exiting DPM failed\r\n");
mp_printf(&mp_plat_print, "qspi flash: exiting DPM failed\r\n");
#endif
}
// restore sck_delay
@ -327,6 +316,5 @@ void qspi_flash_exit_sleep(void) {
= (NRF_QSPI->IFCONFIG1 & ~QSPI_IFCONFIG1_SCKDELAY_Msk)
| (sck_delay_saved << QSPI_IFCONFIG1_SCKDELAY_Pos);
}
// dbg_dumpQSPIreg();
#endif
}

View File

@ -1,127 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries
*
* 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/mphal.h"
#include "supervisor/serial.h"
#if CIRCUITPY_CONSOLE_BLE
#include "ble_uart.h"
#elif CIRCUITPY_CONSOLE_UART
#include <string.h>
#include "nrf_gpio.h"
#include "nrfx_uarte.h"
#endif
#if CIRCUITPY_CONSOLE_BLE
void serial_init(void) {
ble_uart_init();
}
bool serial_connected(void) {
return ble_uart_connected();
}
char serial_read(void) {
return (char)ble_uart_rx_chr();
}
bool serial_bytes_available(void) {
return ble_uart_stdin_any();
}
void serial_write(const char *text) {
ble_uart_stdout_tx_str(text);
}
#elif CIRCUITPY_CONSOLE_UART
uint8_t serial_received_char;
nrfx_uarte_t serial_instance = NRFX_UARTE_INSTANCE(0);
void serial_init(void) {
nrfx_uarte_config_t config = {
.pseltxd = MICROPY_HW_UART_TX,
.pselrxd = MICROPY_HW_UART_RX,
.pselcts = NRF_UARTE_PSEL_DISCONNECTED,
.pselrts = NRF_UARTE_PSEL_DISCONNECTED,
.p_context = NULL,
.hwfc = NRF_UARTE_HWFC_DISABLED,
.parity = NRF_UARTE_PARITY_EXCLUDED,
.baudrate = NRF_UARTE_BAUDRATE_115200,
.interrupt_priority = 7
};
nrfx_uarte_uninit(&serial_instance);
const nrfx_err_t err = nrfx_uarte_init(&serial_instance, &config, NULL); // no callback for blocking mode
if (err != NRFX_SUCCESS) {
NRFX_ASSERT(err);
}
// enabled receiving
nrf_uarte_task_trigger(serial_instance.p_reg, NRF_UARTE_TASK_STARTRX);
}
bool serial_connected(void) {
return true;
}
char serial_read(void) {
uint8_t data;
nrfx_uarte_rx(&serial_instance, &data, 1);
return data;
}
bool serial_bytes_available(void) {
return nrf_uarte_event_check(serial_instance.p_reg, NRF_UARTE_EVENT_RXDRDY);
}
void serial_write(const char *text) {
serial_write_substring(text, strlen(text));
}
void serial_write_substring(const char *text, uint32_t len) {
if (len == 0) {
return;
}
// EasyDMA can only access SRAM
uint8_t *tx_buf = (uint8_t *)text;
if (!nrfx_is_in_ram(text)) {
tx_buf = (uint8_t *)m_malloc(len, false);
memcpy(tx_buf, text, len);
}
nrfx_uarte_tx(&serial_instance, tx_buf, len);
if (!nrfx_is_in_ram(text)) {
m_free(tx_buf);
}
}
#endif // CIRCUITPY_CONSOLE_UART

View File

@ -173,7 +173,6 @@ SRC_C += \
fatfs_port.c \
supervisor/stub/filesystem.c \
supervisor/stub/safe_mode.c \
supervisor/stub/serial.c \
supervisor/stub/stack.c \
supervisor/shared/translate.c \
$(SRC_MOD) \

View File

@ -351,7 +351,7 @@ CFLAGS += -DUSB_NUM_IN_ENDPOINTS=$(USB_NUM_IN_ENDPOINTS)
USB_NUM_OUT_ENDPOINTS ?= $(USB_NUM_ENDPOINT_PAIRS)
CFLAGS += -DUSB_NUM_OUT_ENDPOINTS=$(USB_NUM_OUT_ENDPOINTS)
CIRCUITPY_USB_CDC ?= 1
CIRCUITPY_USB_CDC ?= $(CIRCUITPY_USB)
CFLAGS += -DCIRCUITPY_USB_CDC=$(CIRCUITPY_USB_CDC)
CIRCUITPY_USB_CDC_CONSOLE_ENABLED_DEFAULT ?= 1
CFLAGS += -DCIRCUITPY_USB_CDC_CONSOLE_ENABLED_DEFAULT=$(CIRCUITPY_USB_CDC_CONSOLE_ENABLED_DEFAULT)
@ -359,18 +359,18 @@ CIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT ?= 0
CFLAGS += -DCIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT=$(CIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT)
# HID is available by default, but is not turned on if there are fewer than 5 endpoints.
CIRCUITPY_USB_HID ?= 1
CIRCUITPY_USB_HID ?= $(CIRCUITPY_USB)
CFLAGS += -DCIRCUITPY_USB_HID=$(CIRCUITPY_USB_HID)
CIRCUITPY_USB_HID_ENABLED_DEFAULT ?= $(USB_NUM_ENDPOINT_PAIRS_5_OR_GREATER)
CFLAGS += -DCIRCUITPY_USB_HID_ENABLED_DEFAULT=$(CIRCUITPY_USB_HID_ENABLED_DEFAULT)
# MIDI is available by default, but is not turned on if there are fewer than 8 endpoints.
CIRCUITPY_USB_MIDI ?= 1
CIRCUITPY_USB_MIDI ?= $(CIRCUITPY_USB)
CFLAGS += -DCIRCUITPY_USB_MIDI=$(CIRCUITPY_USB_MIDI)
CIRCUITPY_USB_MIDI_ENABLED_DEFAULT ?= $(USB_NUM_ENDPOINT_PAIRS_8_OR_GREATER)
CFLAGS += -DCIRCUITPY_USB_MIDI_ENABLED_DEFAULT=$(CIRCUITPY_USB_MIDI_ENABLED_DEFAULT)
CIRCUITPY_USB_MSC ?= 1
CIRCUITPY_USB_MSC ?= $(CIRCUITPY_USB)
CFLAGS += -DCIRCUITPY_USB_MSC=$(CIRCUITPY_USB_MSC)
CIRCUITPY_USB_MSC_ENABLED_DEFAULT ?= $(CIRCUITPY_USB_MSC)
CFLAGS += -DCIRCUITPY_USB_MSC_ENABLED_DEFAULT=$(CIRCUITPY_USB_MSC_ENABLED_DEFAULT)

View File

@ -32,3 +32,6 @@ mypy
# For uploading artifacts
awscli
# for combining the Nordic SoftDevice with CircuitPython
intelhex

View File

@ -137,6 +137,14 @@ bool common_hal_storage_disable_usb_drive(void) {
bool common_hal_storage_enable_usb_drive(void) {
return usb_drive_set_enabled(true);
}
#else
bool common_hal_storage_disable_usb_drive(void) {
return false;
}
bool common_hal_storage_enable_usb_drive(void) {
return false;
}
#endif // CIRCUITPY_USB_MSC
STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_args, const mp_obj_t *args) {

View File

@ -161,6 +161,9 @@ void supervisor_bluetooth_init(void) {
common_hal_digitalio_digitalinout_construct(&boot_button, CIRCUITPY_BOOT_BUTTON);
common_hal_digitalio_digitalinout_switch_to_input(&boot_button, PULL_UP);
#endif
#if CIRCUITPY_STATUS_LED
status_led_init();
#endif
uint64_t start_ticks = supervisor_ticks_ms64();
uint64_t diff = 0;
if (ble_mode != 0) {
@ -233,3 +236,13 @@ void supervisor_start_bluetooth(void) {
// Kick off advertisments
supervisor_bluetooth_background();
}
void supervisor_stop_bluetooth(void) {
#if !CIRCUITPY_BLE_FILE_SERVICE && !CIRCUITPY_SERIAL_BLE
return;
#endif
#if CIRCUITPY_SERIAL_BLE
supervisor_stop_bluetooth_serial();
#endif
}

View File

@ -32,5 +32,6 @@
void supervisor_bluetooth_background(void);
void supervisor_bluetooth_init(void);
void supervisor_start_bluetooth(void);
void supervisor_stop_bluetooth(void);
#endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_BLUETOOTH_H

View File

@ -252,7 +252,7 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) {
path[command->path_length] = '\0';
// Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done.
#if CIRCUITPY_USB_MSC
#if CIRCUITPY_USB && CIRCUITPY_USB_MSC
if (storage_usb_enabled() && !usb_msc_lock()) {
response.status = STATUS_ERROR;
common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct write_pacing), NULL, 0);
@ -506,11 +506,13 @@ void supervisor_bluetooth_file_transfer_background(void) {
}
// TODO: If size < 0 return an error.
current_offset += size;
// mp_printf(&mp_plat_print, "buffer[:%d]:", current_offset);
// for (size_t i = 0; i < current_offset; i++) {
// mp_printf(&mp_plat_print, " (%x %c)", current_command[i], current_command[i]);
// }
// mp_printf(&mp_plat_print, "\n");
#if CIRCUITPY_VERBOSE_BLE
mp_printf(&mp_plat_print, "buffer[:%d]:", current_offset);
for (size_t i = 0; i < current_offset; i++) {
mp_printf(&mp_plat_print, " (%x %c)", current_command[i], current_command[i]);
}
mp_printf(&mp_plat_print, "\n");
#endif
uint8_t current_state = current_command[0];
// mp_printf(&mp_plat_print, "current command 0x%02x\n", current_state);
// Check for protocol error.

View File

@ -60,6 +60,9 @@ STATIC bleio_packet_buffer_obj_t _tx_packet_buffer;
STATIC uint32_t _incoming[64];
STATIC bleio_characteristic_buffer_obj_t _rx_buffer;
// Internal enabling so we can disable while printing BLE debugging.
STATIC bool _enabled;
void supervisor_start_bluetooth_serial(void) {
supervisor_ble_serial_service_uuid.base.type = &bleio_uuid_type;
common_hal_bleio_uuid_construct(&supervisor_ble_serial_service_uuid, 0x0001, nordic_uart_base_uuid);
@ -71,6 +74,7 @@ void supervisor_start_bluetooth_serial(void) {
characteristic_list.items = characteristic_list_items;
mp_seq_clear(characteristic_list.items, 0, characteristic_list.alloc, sizeof(*characteristic_list.items));
supervisor_ble_serial_service.base.type = &bleio_service_type;
_common_hal_bleio_service_construct(&supervisor_ble_serial_service, &supervisor_ble_serial_service_uuid, false /* is secondary */, &characteristic_list);
// RX
@ -117,6 +121,18 @@ void supervisor_start_bluetooth_serial(void) {
0.1f,
(uint8_t *)_incoming, sizeof(_incoming) * sizeof(uint32_t),
&rx_static_handler_entry);
_enabled = true;
}
void supervisor_stop_bluetooth_serial(void) {
if (common_hal_bleio_packet_buffer_deinited(&_tx_packet_buffer)) {
return;
}
if (!_enabled) {
return;
}
common_hal_bleio_packet_buffer_flush(&_tx_packet_buffer);
}
bool ble_serial_connected(void) {
@ -124,13 +140,18 @@ bool ble_serial_connected(void) {
}
bool ble_serial_available(void) {
return !common_hal_bleio_characteristic_buffer_deinited(&_rx_buffer) && common_hal_bleio_characteristic_buffer_rx_characters_available(&_rx_buffer);
return _enabled &&
!common_hal_bleio_characteristic_buffer_deinited(&_rx_buffer) &&
common_hal_bleio_characteristic_buffer_rx_characters_available(&_rx_buffer);
}
char ble_serial_read_char(void) {
if (common_hal_bleio_characteristic_buffer_deinited(&_rx_buffer)) {
return -1;
}
if (!_enabled) {
return -1;
}
uint8_t c;
common_hal_bleio_characteristic_buffer_read(&_rx_buffer, &c, 1, NULL);
return c;
@ -140,6 +161,9 @@ void ble_serial_write(const char *text, size_t len) {
if (common_hal_bleio_packet_buffer_deinited(&_tx_packet_buffer)) {
return;
}
if (!_enabled) {
return;
}
size_t sent = 0;
while (sent < len) {
uint16_t packet_size = MIN(len, (size_t)common_hal_bleio_packet_buffer_get_outgoing_packet_length(&_tx_packet_buffer));
@ -151,3 +175,11 @@ void ble_serial_write(const char *text, size_t len) {
sent += written;
}
}
void ble_serial_enable(void) {
_enabled = true;
}
void ble_serial_disable(void) {
_enabled = false;
}

View File

@ -30,10 +30,13 @@
#include <stdbool.h>
void supervisor_start_bluetooth_serial(void);
void supervisor_stop_bluetooth_serial(void);
bool ble_serial_connected(void);
bool ble_serial_available(void);
char ble_serial_read_char(void);
void ble_serial_write(const char *text, size_t len);
void ble_serial_enable(void);
void ble_serial_disable(void);
#endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_BLUETOOTH_SERIAL_H

View File

@ -42,15 +42,9 @@
#include "tusb.h"
#ifdef NRF_DEBUG_PRINT
// XXX these functions are in nrf/supervisor/debug_uart.c
extern void _debug_uart_init(void);
extern void _debug_print_substr(const char *text, uint32_t length);
#endif
/*
* Note: DEBUG_UART currently only works on STM32,
* enabling on another platform will cause a crash.
* Note: DEBUG_UART currently only works on STM32 and nRF.
* Enabling on another platform will cause a crash.
*/
#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
@ -75,17 +69,10 @@ void serial_early_init(void) {
buf_array, true);
common_hal_busio_uart_never_reset(&debug_uart);
#endif
#ifdef NRF_DEBUG_PRINT
_debug_uart_init();
#endif
}
void serial_init(void) {
// USB serial is set up separately.
#ifdef NRF_DEBUG_PRINT
_debug_uart_init();
#endif
}
bool serial_connected(void) {
@ -109,7 +96,7 @@ bool serial_connected(void) {
if (usb_cdc_console_enabled() && tud_cdc_connected()) {
return true;
}
#else
#elif CIRCUITPY_USB
if (tud_cdc_connected()) {
return true;
}
@ -127,13 +114,12 @@ char serial_read(void) {
#endif
#if defined(DEBUG_UART_TX) && defined(DEBUG_UART_RX)
if (tud_cdc_connected() && tud_cdc_available() > 0) {
return (char)tud_cdc_read_char();
if (common_hal_busio_uart_rx_characters_available(&debug_uart)) {
int uart_errcode;
char text;
common_hal_busio_uart_read(&debug_uart, (uint8_t *)&text, 1, &uart_errcode);
return text;
}
int uart_errcode;
char text;
common_hal_busio_uart_read(&debug_uart, (uint8_t *)&text, 1, &uart_errcode);
return text;
#endif
#if CIRCUITPY_SERIAL_BLE
@ -147,7 +133,10 @@ char serial_read(void) {
return -1;
}
#endif
#if CIRCUITPY_USB
return (char)tud_cdc_read_char();
#endif
return -1;
}
bool serial_bytes_available(void) {
@ -173,7 +162,8 @@ bool serial_bytes_available(void) {
if (usb_cdc_console_enabled() && tud_cdc_available() > 0) {
return true;
}
#else
#endif
#if CIRCUITPY_USB
if (tud_cdc_available() > 0) {
return true;
}
@ -202,10 +192,6 @@ void serial_write_substring(const char *text, uint32_t length) {
common_hal_busio_uart_write(&debug_uart, (const uint8_t *)text, length, &uart_errcode);
#endif
#ifdef NRF_DEBUG_PRINT
_debug_print_substr(text, length);
#endif
#if CIRCUITPY_SERIAL_BLE
ble_serial_write(text, length);
#endif
@ -216,6 +202,7 @@ void serial_write_substring(const char *text, uint32_t length) {
}
#endif
#if CIRCUITPY_USB
uint32_t count = 0;
while (count < length && tud_cdc_connected()) {
count += tud_cdc_write(text + count, length - count);
@ -225,6 +212,7 @@ void serial_write_substring(const char *text, uint32_t length) {
}
usb_background();
}
#endif
}
void serial_write(const char *text) {

View File

@ -72,7 +72,9 @@ endif
ifeq ($(CIRCUITPY_USB),0)
ifeq ($(wildcard supervisor/serial.c),)
SRC_SUPERVISOR += supervisor/stub/serial.c
SRC_SUPERVISOR += supervisor/shared/serial.c \
supervisor/shared/workflow.c \
else
SRC_SUPERVISOR += supervisor/serial.c
endif

View File

@ -30,6 +30,7 @@ HEX_UF2 = ("hex", "uf2")
SPK = ("spk",)
DFU = ("dfu",)
BIN_DFU = ("bin", "dfu")
COMBINED_HEX = ("combined.hex",)
# Default extensions
extension_by_port = {
@ -61,6 +62,7 @@ extension_by_board = {
"pca10056": BIN_UF2,
"pca10059": BIN_UF2,
"electronut_labs_blip": HEX,
"microbit_v2": COMBINED_HEX,
# stm32
"meowbit_v121": UF2,
}