Merge pull request #13 from adafruit/main

Update from adafruit
This commit is contained in:
DavePutz 2020-07-18 12:08:26 -05:00 committed by GitHub
commit ac5ad030f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 799 additions and 366 deletions

View File

@ -274,6 +274,7 @@ jobs:
- "teensy41" - "teensy41"
- "teknikio_bluebird" - "teknikio_bluebird"
- "thunderpack" - "thunderpack"
- "tinkeringtech_scoutmakes_azul"
- "trellis_m4_express" - "trellis_m4_express"
- "trinket_m0" - "trinket_m0"
- "trinket_m0_haxpress" - "trinket_m0_haxpress"

View File

@ -5,6 +5,8 @@
#include <stdio.h> #include <stdio.h>
#include "py/binary.h"
#include "py/objarray.h"
#include "py/objlist.h" #include "py/objlist.h"
#include "py/objstringio.h" #include "py/objstringio.h"
#include "py/parsenum.h" #include "py/parsenum.h"
@ -53,6 +55,8 @@ typedef struct _ujson_stream_t {
mp_obj_t stream_obj; mp_obj_t stream_obj;
mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
int errcode; int errcode;
mp_obj_t python_readinto[2 + 1];
mp_obj_array_t bytearray_obj;
byte cur; byte cur;
} ujson_stream_t; } ujson_stream_t;
@ -73,9 +77,39 @@ STATIC byte ujson_stream_next(ujson_stream_t *s) {
return s->cur; return s->cur;
} }
STATIC mp_uint_t ujson_python_readinto(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) {
ujson_stream_t* s = obj;
s->bytearray_obj.items = buf;
s->bytearray_obj.len = size;
*errcode = 0;
mp_obj_t ret = mp_call_method_n_kw(1, 0, s->python_readinto);
if (ret == mp_const_none) {
*errcode = MP_EAGAIN;
return MP_STREAM_ERROR;
}
return mp_obj_get_int(ret);
}
STATIC mp_obj_t _mod_ujson_load(mp_obj_t stream_obj, bool return_first_json) { STATIC mp_obj_t _mod_ujson_load(mp_obj_t stream_obj, bool return_first_json) {
const mp_stream_p_t *stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ); const mp_stream_p_t *stream_p = mp_proto_get(MP_QSTR_protocol_stream, stream_obj);
ujson_stream_t s = {stream_obj, stream_p->read, 0, 0}; ujson_stream_t s;
if (stream_p == NULL) {
mp_load_method(stream_obj, MP_QSTR_readinto, s.python_readinto);
s.bytearray_obj.base.type = &mp_type_bytearray;
s.bytearray_obj.typecode = BYTEARRAY_TYPECODE;
s.bytearray_obj.free = 0;
// len and items are set at read time
s.python_readinto[2] = MP_OBJ_FROM_PTR(&s.bytearray_obj);
s.stream_obj = &s;
s.read = ujson_python_readinto;
} else {
stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ);
s.stream_obj = stream_obj;
s.read = stream_p->read;
s.errcode = 0;
s.cur = 0;
}
JSON_DEBUG("got JSON stream\n"); JSON_DEBUG("got JSON stream\n");
vstr_t vstr; vstr_t vstr;
vstr_init(&vstr, 8); vstr_init(&vstr, 8);

View File

@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"

View File

@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"

View File

@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"

View File

@ -4,7 +4,6 @@
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"

View File

@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"

View File

@ -3,7 +3,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 0.1\n" "Project-Id-Version: 0.1\n"

View File

@ -2,7 +2,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"

View File

@ -2,7 +2,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"

View File

@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"

View File

@ -2,7 +2,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"

View File

@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"

View File

@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"

View File

@ -2,7 +2,6 @@
# SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: circuitpython-cn\n" "Project-Id-Version: circuitpython-cn\n"

7
main.c
View File

@ -45,6 +45,7 @@
#include "background.h" #include "background.h"
#include "mpconfigboard.h" #include "mpconfigboard.h"
#include "supervisor/background_callback.h"
#include "supervisor/cpu.h" #include "supervisor/cpu.h"
#include "supervisor/memory.h" #include "supervisor/memory.h"
#include "supervisor/port.h" #include "supervisor/port.h"
@ -100,8 +101,6 @@ void start_mp(supervisor_allocation* heap) {
reset_status_led(); reset_status_led();
autoreload_stop(); autoreload_stop();
background_tasks_reset();
// Stack limit should be less than real stack size, so we have a chance // Stack limit should be less than real stack size, so we have a chance
// to recover from limit hit. (Limit is measured in bytes.) // to recover from limit hit. (Limit is measured in bytes.)
mp_stack_ctrl_init(); mp_stack_ctrl_init();
@ -161,6 +160,8 @@ void stop_mp(void) {
MP_STATE_VM(vfs_cur) = vfs; MP_STATE_VM(vfs_cur) = vfs;
#endif #endif
background_callback_reset();
gc_deinit(); gc_deinit();
} }
@ -492,6 +493,8 @@ void gc_collect(void) {
// have lost their references in the VM even though they are mounted. // have lost their references in the VM even though they are mounted.
gc_collect_root((void**)&MP_STATE_VM(vfs_mount_table), sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t)); gc_collect_root((void**)&MP_STATE_VM(vfs_mount_table), sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t));
background_callback_gc_collect();
#if CIRCUITPY_DISPLAYIO #if CIRCUITPY_DISPLAYIO
displayio_gc_collect(); displayio_gc_collect();
#endif #endif

View File

@ -31,7 +31,7 @@
#include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/RawSample.h"
#include "shared-bindings/audiocore/WaveFile.h" #include "shared-bindings/audiocore/WaveFile.h"
#include "supervisor/shared/tick.h" #include "supervisor/background_callback.h"
#include "py/mpstate.h" #include "py/mpstate.h"
#include "py/runtime.h" #include "py/runtime.h"
@ -61,7 +61,6 @@ void audio_dma_free_channel(uint8_t channel) {
assert(audio_dma_allocated[channel]); assert(audio_dma_allocated[channel]);
audio_dma_disable_channel(channel); audio_dma_disable_channel(channel);
audio_dma_allocated[channel] = false; audio_dma_allocated[channel] = false;
supervisor_disable_tick();
} }
void audio_dma_disable_channel(uint8_t channel) { void audio_dma_disable_channel(uint8_t channel) {
@ -73,7 +72,6 @@ void audio_dma_disable_channel(uint8_t channel) {
void audio_dma_enable_channel(uint8_t channel) { void audio_dma_enable_channel(uint8_t channel) {
if (channel >= AUDIO_DMA_CHANNEL_COUNT) if (channel >= AUDIO_DMA_CHANNEL_COUNT)
return; return;
supervisor_enable_tick();
dma_enable_channel(channel); dma_enable_channel(channel);
} }
@ -259,6 +257,15 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
dma->beat_size *= 2; dma->beat_size *= 2;
} }
#ifdef SAM_D5X_E5X
int irq = dma->event_channel < 4 ? EVSYS_0_IRQn + dma->event_channel : EVSYS_4_IRQn;
#else
int irq = EVSYS_IRQn;
#endif
NVIC_DisableIRQ(irq);
NVIC_ClearPendingIRQ(irq);
DmacDescriptor* first_descriptor = dma_descriptor(dma_channel); DmacDescriptor* first_descriptor = dma_descriptor(dma_channel);
setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address); setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address);
if (single_buffer) { if (single_buffer) {
@ -281,6 +288,8 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
dma_configure(dma_channel, dma_trigger_source, true); dma_configure(dma_channel, dma_trigger_source, true);
audio_dma_enable_channel(dma_channel); audio_dma_enable_channel(dma_channel);
NVIC_EnableIRQ(irq);
return AUDIO_DMA_OK; return AUDIO_DMA_OK;
} }
@ -321,9 +330,6 @@ void audio_dma_reset(void) {
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) { for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
audio_dma_state[i] = NULL; audio_dma_state[i] = NULL;
audio_dma_pending[i] = false; audio_dma_pending[i] = false;
if (audio_dma_allocated[i]) {
supervisor_disable_tick();
}
audio_dma_allocated[i] = false; audio_dma_allocated[i] = false;
audio_dma_disable_channel(i); audio_dma_disable_channel(i);
dma_descriptor(i)->BTCTRL.bit.VALID = false; dma_descriptor(i)->BTCTRL.bit.VALID = false;
@ -343,29 +349,39 @@ bool audio_dma_get_playing(audio_dma_t* dma) {
return (status & DMAC_CHINTFLAG_TERR) == 0; return (status & DMAC_CHINTFLAG_TERR) == 0;
} }
// WARN(tannewt): DO NOT print from here. Printing calls background tasks such as this and causes a // WARN(tannewt): DO NOT print from here, or anything it calls. Printing calls
// stack overflow. // background tasks such as this and causes a stack overflow.
STATIC void dma_callback_fun(void *arg) {
audio_dma_t* dma = arg;
if (dma == NULL) {
return;
}
void audio_dma_background(void) { audio_dma_load_next_block(dma);
}
void evsyshandler_common(void) {
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) { for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
if (audio_dma_pending[i]) {
continue;
}
audio_dma_t* dma = audio_dma_state[i]; audio_dma_t* dma = audio_dma_state[i];
if (dma == NULL) { if (dma == NULL) {
continue; continue;
} }
bool block_done = event_interrupt_active(dma->event_channel); bool block_done = event_interrupt_active(dma->event_channel);
if (!block_done) { if (!block_done) {
continue; continue;
} }
background_callback_add(&dma->callback, dma_callback_fun, (void*)dma);
// audio_dma_load_next_block() can call Python code, which can call audio_dma_background()
// recursively at the next background processing time. So disallow recursive calls to here.
audio_dma_pending[i] = true;
audio_dma_load_next_block(dma);
audio_dma_pending[i] = false;
} }
} }
#ifdef SAM_D5X_E5X
void EVSYS_0_Handler(void) { evsyshandler_common(); }
void EVSYS_1_Handler(void) { evsyshandler_common(); }
void EVSYS_2_Handler(void) { evsyshandler_common(); }
void EVSYS_3_Handler(void) { evsyshandler_common(); }
void EVSYS_4_Handler(void) { evsyshandler_common(); }
#else
void EVSYS_Handler(void) { evsyshandler_common(); }
#endif
#endif #endif

View File

@ -31,6 +31,7 @@
#include "py/obj.h" #include "py/obj.h"
#include "shared-module/audiocore/RawSample.h" #include "shared-module/audiocore/RawSample.h"
#include "shared-module/audiocore/WaveFile.h" #include "shared-module/audiocore/WaveFile.h"
#include "supervisor/background_callback.h"
typedef struct { typedef struct {
mp_obj_t sample; mp_obj_t sample;
@ -49,6 +50,7 @@ typedef struct {
uint8_t* second_buffer; uint8_t* second_buffer;
bool first_descriptor_free; bool first_descriptor_free;
DmacDescriptor* second_descriptor; DmacDescriptor* second_descriptor;
background_callback_t callback;
} audio_dma_t; } audio_dma_t;
typedef enum { typedef enum {

View File

@ -39,63 +39,21 @@
#include "shared-module/displayio/__init__.h" #include "shared-module/displayio/__init__.h"
#endif #endif
volatile uint64_t last_finished_tick = 0;
bool stack_ok_so_far = true;
static bool running_background_tasks = false;
#ifdef MONITOR_BACKGROUND_TASKS #ifdef MONITOR_BACKGROUND_TASKS
// PB03 is physical pin "SCL" on the Metro M4 express // PB03 is physical pin "SCL" on the Metro M4 express
// so you can't use this code AND an i2c peripheral // so you can't use this code AND an i2c peripheral
// at the same time unless you change this // at the same time unless you change this
STATIC void start_background_task(void) { void port_start_background_task(void) {
REG_PORT_DIRSET1 = (1<<3); REG_PORT_DIRSET1 = (1<<3);
REG_PORT_OUTSET1 = (1<<3); REG_PORT_OUTSET1 = (1<<3);
} }
STATIC void finish_background_task(void) { void port_finish_background_task(void) {
REG_PORT_OUTCLR1 = (1<<3); REG_PORT_OUTCLR1 = (1<<3);
} }
#else #else
STATIC void start_background_task(void) {} void port_start_background_task(void) {}
STATIC void finish_background_task(void) {} void port_finish_background_task(void) {}
#endif #endif
void background_tasks_reset(void) { void port_background_task(void) {}
running_background_tasks = false;
}
void run_background_tasks(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}
start_background_task();
assert_heap_ok();
running_background_tasks = true;
#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
audio_dma_background();
#endif
#if CIRCUITPY_DISPLAYIO
displayio_background();
#endif
#if CIRCUITPY_NETWORK
network_module_background();
#endif
filesystem_background();
usb_background();
running_background_tasks = false;
assert_heap_ok();
last_finished_tick = port_get_raw_ticks(NULL);
finish_background_task();
}
bool background_tasks_ok(void) {
return port_get_raw_ticks(NULL) - last_finished_tick < 1024;
}

View File

@ -29,9 +29,4 @@
#include <stdbool.h> #include <stdbool.h>
void background_tasks_reset(void);
void run_background_tasks(void);
void run_background_vm_tasks(void);
bool background_tasks_ok(void);
#endif // MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H #endif // MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H

View File

@ -9,3 +9,10 @@ CHIP_FAMILY = samd21
INTERNAL_FLASH_FILESYSTEM = 1 INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = NONE LONGINT_IMPL = NONE
CIRCUITPY_FULL_BUILD = 0 CIRCUITPY_FULL_BUILD = 0
# Tweak inlining depending on language.
ifeq ($(TRANSLATION), zh_Latn_pinyin)
CFLAGS_INLINE_LIMIT = 45
else
CFLAGS_INLINE_LIMIT = 70
endif

View File

@ -46,6 +46,7 @@
#include "hpl_gclk_config.h" #include "hpl_gclk_config.h"
#include "shared-bindings/time/__init__.h" #include "shared-bindings/time/__init__.h"
#include "supervisor/shared/tick.h"
#include "supervisor/shared/translate.h" #include "supervisor/shared/translate.h"
#ifdef SAMD21 #ifdef SAMD21
@ -132,7 +133,7 @@ void frequencyin_interrupt_handler(uint8_t index) {
} }
// Check if we've reached the upper limit of detection // Check if we've reached the upper limit of detection
if (!background_tasks_ok() || self->errored_too_fast) { if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
self->errored_too_fast = true; self->errored_too_fast = true;
frequencyin_emergency_cancel_capture(i); frequencyin_emergency_cancel_capture(i);
} }

View File

@ -42,6 +42,7 @@
#include "samd/timers.h" #include "samd/timers.h"
#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/pulseio/PulseIn.h" #include "shared-bindings/pulseio/PulseIn.h"
#include "supervisor/shared/tick.h"
#include "supervisor/shared/translate.h" #include "supervisor/shared/translate.h"
// This timer is shared amongst all PulseIn objects as a higher resolution clock. // This timer is shared amongst all PulseIn objects as a higher resolution clock.
@ -87,7 +88,7 @@ void pulsein_interrupt_handler(uint8_t channel) {
uint32_t current_count = tc->COUNT16.COUNT.reg; uint32_t current_count = tc->COUNT16.COUNT.reg;
pulseio_pulsein_obj_t* self = get_eic_channel_data(channel); pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
if (!background_tasks_ok() || self->errored_too_fast) { if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
self->errored_too_fast = true; self->errored_too_fast = true;
common_hal_pulseio_pulsein_pause(self); common_hal_pulseio_pulsein_pause(self);
return; return;

View File

@ -29,6 +29,8 @@
#include "hpl/gclk/hpl_gclk_base.h" #include "hpl/gclk/hpl_gclk_base.h"
#include "hal_gpio.h" #include "hal_gpio.h"
#include "lib/tinyusb/src/device/usbd.h" #include "lib/tinyusb/src/device/usbd.h"
#include "supervisor/background_callback.h"
#include "supervisor/usb.h"
void init_usb_hardware(void) { void init_usb_hardware(void) {
#ifdef SAMD21 #ifdef SAMD21
@ -61,24 +63,24 @@ void init_usb_hardware(void) {
#ifdef SAMD21 #ifdef SAMD21
void USB_Handler(void) { void USB_Handler(void) {
tud_int_handler(0); usb_irq_handler();
} }
#endif #endif
#ifdef SAM_D5X_E5X #ifdef SAM_D5X_E5X
void USB_0_Handler (void) { void USB_0_Handler (void) {
tud_int_handler(0); usb_irq_handler();
} }
void USB_1_Handler (void) { void USB_1_Handler (void) {
tud_int_handler(0); usb_irq_handler();
} }
void USB_2_Handler (void) { void USB_2_Handler (void) {
tud_int_handler(0); usb_irq_handler();
} }
void USB_3_Handler (void) { void USB_3_Handler (void) {
tud_int_handler(0); usb_irq_handler();
} }
#endif #endif

View File

@ -30,24 +30,6 @@
#include "supervisor/filesystem.h" #include "supervisor/filesystem.h"
#include "supervisor/shared/stack.h" #include "supervisor/shared/stack.h"
static bool running_background_tasks = false; void port_background_task(void) {}
void port_start_background_task(void) {}
void background_tasks_reset(void) { void port_finish_background_task(void) {}
running_background_tasks = false;
}
void run_background_tasks(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}
assert_heap_ok();
running_background_tasks = true;
usb_background();
filesystem_background();
running_background_tasks = false;
assert_heap_ok();
}

View File

@ -27,7 +27,4 @@
#ifndef MICROPY_INCLUDED_CXD56_BACKGROUND_H #ifndef MICROPY_INCLUDED_CXD56_BACKGROUND_H
#define MICROPY_INCLUDED_CXD56_BACKGROUND_H #define MICROPY_INCLUDED_CXD56_BACKGROUND_H
void background_tasks_reset(void);
void run_background_tasks(void);
#endif // MICROPY_INCLUDED_CXD56_BACKGROUND_H #endif // MICROPY_INCLUDED_CXD56_BACKGROUND_H

View File

@ -217,8 +217,8 @@ $(BUILD)/esp-idf/config/sdkconfig.h: boards/$(BOARD)/sdkconfig | $(BUILD)/esp-id
# build a lib # build a lib
# Adding -d explain -j 1 -v to the ninja line will output debug info # Adding -d explain -j 1 -v to the ninja line will output debug info
$(BUILD)/esp-idf/esp-idf/%.a: $(BUILD)/esp-idf/config/sdkconfig.h #$(BUILD)/esp-idf/esp-idf/%.a: $(BUILD)/esp-idf/config/sdkconfig.h
ninja -C $(BUILD)/esp-idf esp-idf/$*.a # ninja -C $(BUILD)/esp-idf esp-idf/$*.a
$(BUILD)/esp-idf/esp-idf/esp32s2/esp32s2_out.ld: $(BUILD)/esp-idf/config/sdkconfig.h $(BUILD)/esp-idf/esp-idf/esp32s2/esp32s2_out.ld: $(BUILD)/esp-idf/config/sdkconfig.h
ninja -C $(BUILD)/esp-idf esp-idf/esp32s2/esp32s2_out.ld ninja -C $(BUILD)/esp-idf esp-idf/esp32s2/esp32s2_out.ld
@ -230,9 +230,6 @@ $(BUILD)/esp-idf/esp-idf/esp32s2/ld/esp32s2.project.ld: $(BUILD)/esp-idf/config/
$(BUILD)/esp-idf/partition_table/partition-table.bin: $(BUILD)/esp-idf/config/sdkconfig.h $(BUILD)/esp-idf/partition_table/partition-table.bin: $(BUILD)/esp-idf/config/sdkconfig.h
IDF_PATH=$(IDF_PATH) ninja -C $(BUILD)/esp-idf partition_table/partition-table.bin IDF_PATH=$(IDF_PATH) ninja -C $(BUILD)/esp-idf partition_table/partition-table.bin
$(BUILD)/esp-idf/bootloader/bootloader.bin: $(BUILD)/esp-idf/config/sdkconfig.h
ninja -C $(BUILD)/esp-idf bootloader/bootloader.bin
# run menuconfig # run menuconfig
menuconfig: $(BUILD)/esp-idf/config menuconfig: $(BUILD)/esp-idf/config
ninja -C $(BUILD)/esp-idf menuconfig ninja -C $(BUILD)/esp-idf menuconfig
@ -260,7 +257,18 @@ FLASH_FLAGS = --flash_mode $(CIRCUITPY_ESP_FLASH_MODE) --flash_freq $(CIRCUITPY_
all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2
$(BUILD)/firmware.elf: $(OBJ) | $(ESP_IDF_COMPONENTS_EXPANDED) $(ESP_AUTOGEN_LD) .PHONY: esp-idf-stamp
esp-idf-stamp: $(BUILD)/esp-idf/config/sdkconfig.h
ninja -C $(BUILD)/esp-idf \
bootloader/bootloader.bin \
esp-idf/bootloader_support/libbootloader_support.a \
esp-idf/esp32s2/ld/esp32s2.project.ld \
esp-idf/esp_system/libesp_system.a \
esp-idf/freertos/libfreertos.a \
esp-idf/log/liblog.a \
esp-idf/xtensa/libxtensa.a
$(BUILD)/firmware.elf: $(OBJ) | esp-idf-stamp
$(STEPECHO) "LINK $@" $(STEPECHO) "LINK $@"
$(Q)$(CC) -o $@ $(LDFLAGS) $^ $(ESP_IDF_COMPONENTS_EXPANDED) $(BINARY_BLOBS) build-$(BOARD)/esp-idf/esp-idf/newlib/libnewlib.a -u newlib_include_pthread_impl $(Q)$(CC) -o $@ $(LDFLAGS) $^ $(ESP_IDF_COMPONENTS_EXPANDED) $(BINARY_BLOBS) build-$(BOARD)/esp-idf/esp-idf/newlib/libnewlib.a -u newlib_include_pthread_impl
# $(Q)$(SIZE) $@ | $(PYTHON3) $(TOP)/tools/build_memory_info.py $(BUILD)/esp-idf/esp-idf/esp32s2/esp32s2_out.ld # $(Q)$(SIZE) $@ | $(PYTHON3) $(TOP)/tools/build_memory_info.py $(BUILD)/esp-idf/esp-idf/esp32s2/esp32s2_out.ld
@ -271,7 +279,7 @@ $(BUILD)/circuitpython-firmware.bin: $(BUILD)/firmware.elf
# $(Q)$(OBJCOPY) -O binary $^ $@ # $(Q)$(OBJCOPY) -O binary $^ $@
# $(Q)$(OBJCOPY) -O binary -j .vectors -j .text -j .data $^ $@ # $(Q)$(OBJCOPY) -O binary -j .vectors -j .text -j .data $^ $@
$(BUILD)/firmware.bin: $(BUILD)/esp-idf/partition_table/partition-table.bin $(BUILD)/esp-idf/bootloader/bootloader.bin $(BUILD)/circuitpython-firmware.bin $(BUILD)/firmware.bin: $(BUILD)/circuitpython-firmware.bin | esp-idf-stamp
$(Q)$(PYTHON) ../../tools/join_bins.py $@ 0x1000 $(BUILD)/esp-idf/bootloader/bootloader.bin 0x8000 $(BUILD)/esp-idf/partition_table/partition-table.bin 0x10000 $(BUILD)/circuitpython-firmware.bin $(Q)$(PYTHON) ../../tools/join_bins.py $@ 0x1000 $(BUILD)/esp-idf/bootloader/bootloader.bin 0x8000 $(BUILD)/esp-idf/partition_table/partition-table.bin 0x10000 $(BUILD)/circuitpython-firmware.bin
$(BUILD)/firmware.uf2: $(BUILD)/circuitpython-firmware.bin $(BUILD)/firmware.uf2: $(BUILD)/circuitpython-firmware.bin

View File

@ -35,27 +35,12 @@
#include "shared-module/displayio/__init__.h" #include "shared-module/displayio/__init__.h"
#endif #endif
static bool running_background_tasks = false;
void background_tasks_reset(void) {
running_background_tasks = false;
}
void run_background_tasks(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}
void port_background_task(void) {
// Zero delay in case FreeRTOS wants to switch to something else. // Zero delay in case FreeRTOS wants to switch to something else.
vTaskDelay(0); vTaskDelay(0);
running_background_tasks = true;
filesystem_background();
#if CIRCUITPY_DISPLAYIO
displayio_background();
#endif
running_background_tasks = false;
assert_heap_ok();
} }
void port_start_background_task(void) {}
void port_finish_background_task(void) {}

View File

@ -29,7 +29,4 @@
#include <stdbool.h> #include <stdbool.h>
void background_tasks_reset(void);
void run_background_tasks(void);
#endif // MICROPY_INCLUDED_ESP32S2_BACKGROUND_H #endif // MICROPY_INCLUDED_ESP32S2_BACKGROUND_H

View File

@ -26,10 +26,14 @@
*/ */
#include <math.h> #include <math.h>
#include <string.h>
#include "common-hal/microcontroller/Processor.h" #include "common-hal/microcontroller/Processor.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "supervisor/shared/translate.h" #include "supervisor/shared/translate.h"
#include "soc/efuse_reg.h"
float common_hal_mcu_processor_get_temperature(void) { float common_hal_mcu_processor_get_temperature(void) {
return NAN; return NAN;
} }
@ -42,5 +46,23 @@ uint32_t common_hal_mcu_processor_get_frequency(void) {
return 0; return 0;
} }
void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { STATIC uint8_t swap_nibbles(uint8_t v) {
return ((v << 4) | (v >> 4)) & 0xff;
}
void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) {
memset(raw_id, 0, COMMON_HAL_MCU_PROCESSOR_UID_LENGTH);
uint8_t *ptr = &raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH-1];
// MAC address contains 48 bits (6 bytes), 32 in the low order word
uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SPI_SYS_0_REG);
*ptr-- = swap_nibbles(mac_address_part & 0xff); mac_address_part >>= 8;
*ptr-- = swap_nibbles(mac_address_part & 0xff); mac_address_part >>= 8;
*ptr-- = swap_nibbles(mac_address_part & 0xff); mac_address_part >>= 8;
*ptr-- = swap_nibbles(mac_address_part & 0xff);
// and 16 in the high order word
mac_address_part = REG_READ(EFUSE_RD_MAC_SPI_SYS_1_REG);
*ptr-- = swap_nibbles(mac_address_part & 0xff); mac_address_part >>= 8;
*ptr-- = swap_nibbles(mac_address_part & 0xff);
} }

View File

@ -27,7 +27,7 @@
#ifndef MICROPY_INCLUDED_LITEX_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H #ifndef MICROPY_INCLUDED_LITEX_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H
#define MICROPY_INCLUDED_LITEX_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H #define MICROPY_INCLUDED_LITEX_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H
#define COMMON_HAL_MCU_PROCESSOR_UID_LENGTH 15 #define COMMON_HAL_MCU_PROCESSOR_UID_LENGTH 6
#include "py/obj.h" #include "py/obj.h"

View File

@ -7,7 +7,7 @@ MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz
INTERNAL_LIBM = 1 INTERNAL_LIBM = 1
# Chip supplied serial number, in bytes # Chip supplied serial number, in bytes
USB_SERIAL_NUMBER_LENGTH = 30 USB_SERIAL_NUMBER_LENGTH = 12
# Longints can be implemented as mpz, as longlong, or not # Longints can be implemented as mpz, as longlong, or not
LONGINT_IMPL = MPZ LONGINT_IMPL = MPZ

View File

@ -29,32 +29,6 @@
#include "supervisor/usb.h" #include "supervisor/usb.h"
#include "supervisor/shared/stack.h" #include "supervisor/shared/stack.h"
#if CIRCUITPY_DISPLAYIO void port_background_task(void) {}
#include "shared-module/displayio/__init__.h" void port_start_background_task(void) {}
#endif void port_finish_background_task(void) {}
static bool running_background_tasks = false;
void background_tasks_reset(void) {
running_background_tasks = false;
}
void run_background_tasks(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}
running_background_tasks = true;
filesystem_background();
#if USB_AVAILABLE
usb_background();
#endif
#if CIRCUITPY_DISPLAYIO
displayio_background();
#endif
running_background_tasks = false;
assert_heap_ok();
}

View File

@ -27,9 +27,4 @@
#ifndef MICROPY_INCLUDED_LITEX_BACKGROUND_H #ifndef MICROPY_INCLUDED_LITEX_BACKGROUND_H
#define MICROPY_INCLUDED_LITEX_BACKGROUND_H #define MICROPY_INCLUDED_LITEX_BACKGROUND_H
#include <stdbool.h>
void background_tasks_reset(void);
void run_background_tasks(void);
#endif // MICROPY_INCLUDED_LITEX_BACKGROUND_H #endif // MICROPY_INCLUDED_LITEX_BACKGROUND_H

View File

@ -31,6 +31,7 @@
#include "py/mphal.h" #include "py/mphal.h"
#include "py/mpstate.h" #include "py/mpstate.h"
#include "py/gc.h" #include "py/gc.h"
#include "supervisor/usb.h"
#include "csr.h" #include "csr.h"
#include "generated/soc.h" #include "generated/soc.h"
@ -49,7 +50,7 @@ void isr(void) {
#ifdef CFG_TUSB_MCU #ifdef CFG_TUSB_MCU
if (irqs & (1 << USB_INTERRUPT)) if (irqs & (1 << USB_INTERRUPT))
tud_int_handler(0); usb_irq_handler();
#endif #endif
if (irqs & (1 << TIMER0_INTERRUPT)) if (irqs & (1 << TIMER0_INTERRUPT))
SysTick_Handler(); SysTick_Handler();

View File

@ -24,58 +24,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "background.h"
//#include "audio_dma.h" #include "supervisor/port.h"
#include "supervisor/filesystem.h"
#include "supervisor/shared/tick.h"
#include "supervisor/usb.h"
#include "py/runtime.h"
#include "shared-module/network/__init__.h"
#include "supervisor/linker.h"
#include "supervisor/shared/stack.h"
#ifdef CIRCUITPY_DISPLAYIO
#include "shared-module/displayio/__init__.h"
#endif
volatile uint64_t last_finished_tick = 0;
bool stack_ok_so_far = true;
static bool running_background_tasks = false;
void background_tasks_reset(void) {
running_background_tasks = false;
}
void PLACE_IN_ITCM(run_background_tasks)(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}
assert_heap_ok();
running_background_tasks = true;
void port_background_task(void) {
#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO #if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
audio_dma_background(); audio_dma_background();
#endif #endif
#if CIRCUITPY_DISPLAYIO
displayio_background();
#endif
#if CIRCUITPY_NETWORK
network_module_background();
#endif
filesystem_background();
usb_background();
running_background_tasks = false;
assert_heap_ok();
last_finished_tick = supervisor_ticks_ms64();
}
bool background_tasks_ok(void) {
return supervisor_ticks_ms64() - last_finished_tick < 1000;
} }
void port_start_background_task(void) {}
void port_finish_background_task(void) {}

View File

@ -28,11 +28,4 @@
#ifndef MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H #ifndef MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H
#define MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H #define MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H
#include <stdbool.h>
void background_tasks_reset(void);
void run_background_tasks(void);
void run_background_vm_tasks(void);
bool background_tasks_ok(void);
#endif // MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H #endif // MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H

View File

@ -64,7 +64,7 @@
// // last ms. // // last ms.
// current_us = 1000 - current_us; // current_us = 1000 - current_us;
// pulseio_pulsein_obj_t* self = get_eic_channel_data(channel); // pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
// if (!background_tasks_ok() || self->errored_too_fast) { // if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
// self->errored_too_fast = true; // self->errored_too_fast = true;
// common_hal_pulseio_pulsein_pause(self); // common_hal_pulseio_pulsein_pause(self);
// return; // return;

View File

@ -27,6 +27,7 @@
#include "fsl_clock.h" #include "fsl_clock.h"
#include "tusb.h" #include "tusb.h"
#include "supervisor/usb.h"
void init_usb_hardware(void) { void init_usb_hardware(void) {
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U); CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
@ -56,5 +57,5 @@ void init_usb_hardware(void) {
} }
void USB_OTG1_IRQHandler(void) { void USB_OTG1_IRQHandler(void) {
tud_int_handler(0); usb_irq_handler();
} }

View File

@ -46,36 +46,14 @@
#include "common-hal/_bleio/bonding.h" #include "common-hal/_bleio/bonding.h"
#endif #endif
static bool running_background_tasks = false; void port_start_background_task(void) {}
void port_finish_background_task(void) {}
void background_tasks_reset(void) { void port_background_task(void) {
running_background_tasks = false;
}
void run_background_tasks(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}
running_background_tasks = true;
filesystem_background();
usb_background();
#if CIRCUITPY_AUDIOPWMIO #if CIRCUITPY_AUDIOPWMIO
audiopwmout_background(); audiopwmout_background();
#endif #endif
#if CIRCUITPY_AUDIOBUSIO #if CIRCUITPY_AUDIOBUSIO
i2s_background(); i2s_background();
#endif #endif
#if CIRCUITPY_BLEIO
supervisor_bluetooth_background();
bonding_background();
#endif
#if CIRCUITPY_DISPLAYIO
displayio_background();
#endif
running_background_tasks = false;
assert_heap_ok();
} }

View File

@ -27,9 +27,4 @@
#ifndef MICROPY_INCLUDED_NRF_BACKGROUND_H #ifndef MICROPY_INCLUDED_NRF_BACKGROUND_H
#define MICROPY_INCLUDED_NRF_BACKGROUND_H #define MICROPY_INCLUDED_NRF_BACKGROUND_H
#include <stdbool.h>
void background_tasks_reset(void);
void run_background_tasks(void);
#endif // MICROPY_INCLUDED_NRF_BACKGROUND_H #endif // MICROPY_INCLUDED_NRF_BACKGROUND_H

View File

@ -0,0 +1,25 @@
# Setup
The TinkeringTech ScoutMakes Azul is a bluetooth enabled, feather format, open source platform featuring the nRF52840 from Nordic Semiconductors. The design is based on the Adafruit nRF52840 feather express and uses the Raytac MDBT50Q-1MV2 module.
Schematic, datasheet, pin mapping etc. can be found over [here](https://tinkeringtech.com/scoutmakes-azul).
features:
- ARM Cortex M4F (with HW floating point acceleration) running at 64MHz
- Raytac MDBT50Q-1MV2 BLE module. FCC / IC / TELEC certified module
- 1MB flash and 256KB SRAM
- Native Open Source USB stack pre-programmed with UF2 bootloader and CircuitPython
- 128×32 OLED display
- USB type-C
- On/off power switch
- Bluetooth Low Energy compatible 2.4GHz radio (Details available in the nRF52840 product specification)
- BT5.1 & BT5 Bluetooth Specification Certified
- Supports BT5 Long Range Feature
- 1.7v to 3.3v operation with internal linear and DC/DC voltage regulators
- 21 GPIO, 6 x 12-bit ADC pins, up to 12 PWM outputs (3 PWM modules with 4 outputs each)
- Pin #3 red LED for general purpose blinking,
- Programmable NeoPixel for colorful feedback
- 4 mounting holes
- Reset button
- Works out of the box with Adafruit feather wings.
- Open source design.

View File

@ -0,0 +1,38 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 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 "boards/board.h"
void board_init(void) {
}
bool board_requests_safe_mode(void) {
return false;
}
void reset_board(void) {
}

View File

@ -0,0 +1,63 @@
/*
* 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 "TinkeringTech ScoutMakes Azul"
#define MICROPY_HW_MCU_NAME "nRF52840"
#define MICROPY_HW_NEOPIXEL (&pin_P0_16)
#define MICROPY_HW_LED_STATUS (&pin_P1_15)
#if QSPI_FLASH_FILESYSTEM
#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 17)
#define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(0, 22)
#define MICROPY_QSPI_DATA2 NRF_GPIO_PIN_MAP(0, 23)
#define MICROPY_QSPI_DATA3 NRF_GPIO_PIN_MAP(0, 21)
#define MICROPY_QSPI_SCK NRF_GPIO_PIN_MAP(0, 19)
#define MICROPY_QSPI_CS NRF_GPIO_PIN_MAP(0, 20)
#endif
#if SPI_FLASH_FILESYSTEM
#define SPI_FLASH_MOSI_PIN &pin_P0_17
#define SPI_FLASH_MISO_PIN &pin_P0_22
#define SPI_FLASH_SCK_PIN &pin_P0_19
#define SPI_FLASH_CS_PIN &pin_P0_20
#endif
#define BOARD_HAS_CRYSTAL 1
#define DEFAULT_I2C_BUS_SCL (&pin_P0_11)
#define DEFAULT_I2C_BUS_SDA (&pin_P0_12)
#define DEFAULT_SPI_BUS_SCK (&pin_P0_14)
#define DEFAULT_SPI_BUS_MOSI (&pin_P0_13)
#define DEFAULT_SPI_BUS_MISO (&pin_P0_15)
#define DEFAULT_UART_BUS_RX (&pin_P0_24)
#define DEFAULT_UART_BUS_TX (&pin_P0_25)

View File

@ -0,0 +1,10 @@
USB_VID = 0x239A
USB_PID = 0x80BE
USB_PRODUCT = "TinkeringTech ScoutMakes Azul"
USB_MANUFACTURER = "TinkeringTech LLC"
MCU_CHIP = nrf52840
QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICE_COUNT = 1
EXTERNAL_FLASH_DEVICES = "GD25Q16C"

View File

@ -0,0 +1,53 @@
#include "shared-bindings/board/__init__.h"
STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_04) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_05) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_30) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_28) },
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_02) },
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_03) },
{ MP_ROM_QSTR(MP_QSTR_AREF), MP_ROM_PTR(&pin_P0_31) },
{ MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_P0_29) },
{ MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_P0_29) },
{ MP_ROM_QSTR(MP_QSTR_SWITCH), MP_ROM_PTR(&pin_P1_02) },
{ MP_ROM_QSTR(MP_QSTR_NFC1), MP_ROM_PTR(&pin_P0_09) },
{ MP_ROM_QSTR(MP_QSTR_NFC2), MP_ROM_PTR(&pin_P0_10) },
{ MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_P0_10) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_08) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P0_07) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P0_26) },
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P0_27) },
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P0_06) },
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P0_08) },
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_P1_09) },
{ MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_P0_16) },
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_14) },
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_13) },
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_15) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_25) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_24) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_11) },
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_12) },
{ MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P1_15) },
{ MP_ROM_QSTR(MP_QSTR_RED_LED), MP_ROM_PTR(&pin_P1_15) },
{ MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_P1_15) },
{ MP_ROM_QSTR(MP_QSTR_BLUE_LED), MP_ROM_PTR(&pin_P1_10) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

View File

@ -50,36 +50,34 @@ void common_hal_mcu_delay_us(uint32_t delay) {
static volatile uint32_t nesting_count = 0; static volatile uint32_t nesting_count = 0;
static uint8_t is_nested_critical_region; static uint8_t is_nested_critical_region;
static uint8_t sd_is_enabled = false;
void common_hal_mcu_disable_interrupts() { void common_hal_mcu_disable_interrupts() {
sd_softdevice_is_enabled(&sd_is_enabled); if (nesting_count == 0) {
if (sd_is_enabled) { // Unlike __disable_irq(), this should only be called the first time
// "is_nested_critical_region" is sd's equivalent of our nesting count
// so a nested call would store 0 in the global and make the later
// exit call not actually reenable interrupts
//
// This only disables interrupts of priority 2 through 7; levels 0, 1,
// and 4, are exclusive to softdevice and should never be used, so
// this limitation is not important.
sd_nvic_critical_region_enter(&is_nested_critical_region); sd_nvic_critical_region_enter(&is_nested_critical_region);
} else {
__disable_irq();
__DMB();
nesting_count++;
} }
__DMB();
nesting_count++;
} }
void common_hal_mcu_enable_interrupts() { void common_hal_mcu_enable_interrupts() {
// Don't check here if SD is enabled, because we'll crash if interrupts if (nesting_count == 0) {
// were turned off and sd_softdevice_is_enabled is called. // This is very very bad because it means there was mismatched disable/enables so we
if (sd_is_enabled) { // crash.
sd_nvic_critical_region_exit(is_nested_critical_region); reset_into_safe_mode(HARD_CRASH);
} else {
if (nesting_count == 0) {
// This is very very bad because it means there was mismatched disable/enables so we
// crash.
reset_into_safe_mode(HARD_CRASH);
}
nesting_count--;
if (nesting_count > 0) {
return;
}
__DMB();
__enable_irq();
} }
nesting_count--;
if (nesting_count > 0) {
return;
}
__DMB();
sd_nvic_critical_region_exit(is_nested_critical_region);
} }
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {

View File

@ -313,12 +313,21 @@ void port_sleep_until_interrupt(void) {
// instruction will returned as long as an interrupt is // instruction will returned as long as an interrupt is
// available, even though the actual handler won't fire until // available, even though the actual handler won't fire until
// we re-enable interrupts. // we re-enable interrupts.
common_hal_mcu_disable_interrupts(); //
// We do not use common_hal_mcu_disable_interrupts here because
// we truly require that interrupts be disabled, while
// common_hal_mcu_disable_interrupts actually just masks the
// interrupts that are not required to allow the softdevice to
// function (whether or not SD is enabled)
int nested = __get_PRIMASK();
__disable_irq();
if (!tud_task_event_ready()) { if (!tud_task_event_ready()) {
__DSB(); __DSB();
__WFI(); __WFI();
} }
common_hal_mcu_enable_interrupts(); if (!nested) {
__enable_irq();
}
} }
} }

View File

@ -30,6 +30,7 @@
#include "lib/utils/interrupt_char.h" #include "lib/utils/interrupt_char.h"
#include "lib/mp-readline/readline.h" #include "lib/mp-readline/readline.h"
#include "lib/tinyusb/src/device/usbd.h" #include "lib/tinyusb/src/device/usbd.h"
#include "supervisor/background_callback.h"
#ifdef SOFTDEVICE_PRESENT #ifdef SOFTDEVICE_PRESENT
#include "nrf_sdm.h" #include "nrf_sdm.h"
@ -42,7 +43,9 @@ extern void tusb_hal_nrf_power_event(uint32_t event);
void init_usb_hardware(void) { void init_usb_hardware(void) {
// 2 is max priority (0, 1 are reserved for SD) // 2 is max priority (0, 1, and 4 are reserved for SD)
// 5 is max priority that still allows calling SD functions such as
// sd_softdevice_is_enabled
NVIC_SetPriority(USBD_IRQn, 2); NVIC_SetPriority(USBD_IRQn, 2);
// USB power may already be ready at this time -> no event generated // USB power may already be ready at this time -> no event generated
@ -89,5 +92,5 @@ void init_usb_hardware(void) {
} }
void USBD_IRQHandler(void) { void USBD_IRQHandler(void) {
tud_int_handler(0); usb_irq_handler();
} }

View File

@ -33,28 +33,6 @@
#include "shared-module/displayio/__init__.h" #include "shared-module/displayio/__init__.h"
#endif #endif
static bool running_background_tasks = false; void port_background_task(void) {}
void port_start_background_task(void) {}
void background_tasks_reset(void) { void port_finish_background_task(void) {}
running_background_tasks = false;
}
void run_background_tasks(void) {
// Don't call ourselves recursively.
if (running_background_tasks) {
return;
}
running_background_tasks = true;
filesystem_background();
#if USB_AVAILABLE
usb_background();
#endif
#if CIRCUITPY_DISPLAYIO
displayio_background();
#endif
running_background_tasks = false;
assert_heap_ok();
}

View File

@ -27,9 +27,4 @@
#ifndef MICROPY_INCLUDED_STM32_BACKGROUND_H #ifndef MICROPY_INCLUDED_STM32_BACKGROUND_H
#define MICROPY_INCLUDED_STM32_BACKGROUND_H #define MICROPY_INCLUDED_STM32_BACKGROUND_H
#include <stdbool.h>
void background_tasks_reset(void);
void run_background_tasks(void);
#endif // MICROPY_INCLUDED_STM32_BACKGROUND_H #endif // MICROPY_INCLUDED_STM32_BACKGROUND_H

View File

@ -130,5 +130,5 @@ void init_usb_hardware(void) {
} }
void OTG_FS_IRQHandler(void) { void OTG_FS_IRQHandler(void) {
tud_int_handler(0); usb_irq_handler();
} }

View File

@ -36,11 +36,12 @@
#include "shared-module/audiomp3/MP3Decoder.h" #include "shared-module/audiomp3/MP3Decoder.h"
#include "supervisor/shared/translate.h" #include "supervisor/shared/translate.h"
#include "supervisor/background_callback.h"
#include "lib/mp3/src/mp3common.h" #include "lib/mp3/src/mp3common.h"
#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t)) #define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
/** Fill the input buffer if it is less than half full. /** Fill the input buffer unconditionally.
* *
* Returns true if the input buffer contains any useful data, * Returns true if the input buffer contains any useful data,
* false otherwise. (The input buffer will be padded to the end with * false otherwise. (The input buffer will be padded to the end with
@ -50,10 +51,7 @@
* *
* Sets self->eof if any read of the file returns 0 bytes * Sets self->eof if any read of the file returns 0 bytes
*/ */
STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) { STATIC bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t* self) {
// If buffer is over half full, do nothing
if (self->inbuf_offset < self->inbuf_length/2) return true;
// If we didn't previously reach the end of file, we can try reading now // If we didn't previously reach the end of file, we can try reading now
if (!self->eof) { if (!self->eof) {
@ -87,6 +85,26 @@ STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
return self->inbuf_offset < self->inbuf_length; return self->inbuf_offset < self->inbuf_length;
} }
/** Update the inbuf from a background callback.
*
* This variant is introduced so that at the site of the
* add_background_callback_core call, the prototype matches.
*/
STATIC void mp3file_update_inbuf_cb(void* self) {
mp3file_update_inbuf_always(self);
}
/** Fill the input buffer if it is less than half full.
*
* Returns the same as mp3file_update_inbuf_always.
*/
STATIC bool mp3file_update_inbuf_half(audiomp3_mp3file_obj_t* self) {
// If buffer is over half full, do nothing
if (self->inbuf_offset < self->inbuf_length/2) return true;
return mp3file_update_inbuf_always(self);
}
#define READ_PTR(self) (self->inbuf + self->inbuf_offset) #define READ_PTR(self) (self->inbuf + self->inbuf_offset)
#define BYTES_LEFT(self) (self->inbuf_length - self->inbuf_offset) #define BYTES_LEFT(self) (self->inbuf_length - self->inbuf_offset)
#define CONSUME(self, n) (self->inbuf_offset += n) #define CONSUME(self, n) (self->inbuf_offset += n)
@ -94,7 +112,7 @@ STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
// http://id3.org/d3v2.3.0 // http://id3.org/d3v2.3.0
// http://id3.org/id3v2.3.0 // http://id3.org/id3v2.3.0
STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) { STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) {
mp3file_update_inbuf(self); mp3file_update_inbuf_half(self);
if (BYTES_LEFT(self) < 10) { if (BYTES_LEFT(self) < 10) {
return; return;
} }
@ -129,11 +147,11 @@ STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) {
*/ */
STATIC bool mp3file_find_sync_word(audiomp3_mp3file_obj_t* self) { STATIC bool mp3file_find_sync_word(audiomp3_mp3file_obj_t* self) {
do { do {
mp3file_update_inbuf(self); mp3file_update_inbuf_half(self);
int offset = MP3FindSyncWord(READ_PTR(self), BYTES_LEFT(self)); int offset = MP3FindSyncWord(READ_PTR(self), BYTES_LEFT(self));
if (offset >= 0) { if (offset >= 0) {
CONSUME(self, offset); CONSUME(self, offset);
mp3file_update_inbuf(self); mp3file_update_inbuf_half(self);
return true; return true;
} }
CONSUME(self, MAX(0, BYTES_LEFT(self) - 16)); CONSUME(self, MAX(0, BYTES_LEFT(self) - 16));
@ -209,12 +227,14 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
} }
void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file) { void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file) {
background_callback_begin_critical_section();
self->file = file; self->file = file;
f_lseek(&self->file->fp, 0); f_lseek(&self->file->fp, 0);
self->inbuf_offset = self->inbuf_length; self->inbuf_offset = self->inbuf_length;
self->eof = 0; self->eof = 0;
self->other_channel = -1; self->other_channel = -1;
mp3file_update_inbuf(self); mp3file_update_inbuf_half(self);
mp3file_find_sync_word(self); mp3file_find_sync_word(self);
// It **SHOULD** not be necessary to do this; the buffer should be filled // It **SHOULD** not be necessary to do this; the buffer should be filled
// with fresh content before it is returned by get_buffer(). The fact that // with fresh content before it is returned by get_buffer(). The fact that
@ -224,7 +244,9 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file
memset(self->buffers[0], 0, MAX_BUFFER_LEN); memset(self->buffers[0], 0, MAX_BUFFER_LEN);
memset(self->buffers[1], 0, MAX_BUFFER_LEN); memset(self->buffers[1], 0, MAX_BUFFER_LEN);
MP3FrameInfo fi; MP3FrameInfo fi;
if(!mp3file_get_next_frame_info(self, &fi)) { bool result = mp3file_get_next_frame_info(self, &fi);
background_callback_end_critical_section();
if (!result) {
mp_raise_msg(&mp_type_RuntimeError, mp_raise_msg(&mp_type_RuntimeError,
translate("Failed to parse MP3 file")); translate("Failed to parse MP3 file"));
} }
@ -277,13 +299,15 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t* self,
} }
// We don't reset the buffer index in case we're looping and we have an odd number of buffer // We don't reset the buffer index in case we're looping and we have an odd number of buffer
// loads // loads
background_callback_begin_critical_section();
f_lseek(&self->file->fp, 0); f_lseek(&self->file->fp, 0);
self->inbuf_offset = self->inbuf_length; self->inbuf_offset = self->inbuf_length;
self->eof = 0; self->eof = 0;
self->other_channel = -1; self->other_channel = -1;
mp3file_update_inbuf(self); mp3file_update_inbuf_half(self);
mp3file_skip_id3v2(self); mp3file_skip_id3v2(self);
mp3file_find_sync_word(self); mp3file_find_sync_word(self);
background_callback_end_critical_section();
} }
audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t* self, audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t* self,
@ -321,6 +345,14 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t*
uint8_t *inbuf = READ_PTR(self); uint8_t *inbuf = READ_PTR(self);
int err = MP3Decode(self->decoder, &inbuf, &bytes_left, buffer, 0); int err = MP3Decode(self->decoder, &inbuf, &bytes_left, buffer, 0);
CONSUME(self, BYTES_LEFT(self) - bytes_left); CONSUME(self, BYTES_LEFT(self) - bytes_left);
if (self->inbuf_offset >= 512) {
background_callback_add(
&self->inbuf_fill_cb,
mp3file_update_inbuf_cb,
self);
}
if (err) { if (err) {
return GET_BUFFER_DONE; return GET_BUFFER_DONE;
} }

View File

@ -28,6 +28,7 @@
#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H #ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H #define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
#include "supervisor/background_callback.h"
#include "extmod/vfs_fat.h" #include "extmod/vfs_fat.h"
#include "py/obj.h" #include "py/obj.h"
@ -36,6 +37,7 @@
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
struct _MP3DecInfo *decoder; struct _MP3DecInfo *decoder;
background_callback_t inbuf_fill_cb;
uint8_t* inbuf; uint8_t* inbuf;
uint32_t inbuf_length; uint32_t inbuf_length;
uint32_t inbuf_offset; uint32_t inbuf_offset;

View File

@ -137,7 +137,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self,
// Set the group after initialization otherwise we may send pixels while we delay in // Set the group after initialization otherwise we may send pixels while we delay in
// initialization. // initialization.
common_hal_displayio_display_show(self, &circuitpython_splash); common_hal_displayio_display_show(self, &circuitpython_splash);
self->auto_refresh = auto_refresh; common_hal_displayio_display_set_auto_refresh(self, auto_refresh);
} }
bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) {
@ -383,6 +383,13 @@ bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self
void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self,
bool auto_refresh) { bool auto_refresh) {
self->first_manual_refresh = !auto_refresh; self->first_manual_refresh = !auto_refresh;
if (auto_refresh != self->auto_refresh) {
if (auto_refresh) {
supervisor_enable_tick();
} else {
supervisor_disable_tick();
}
}
self->auto_refresh = auto_refresh; self->auto_refresh = auto_refresh;
} }
@ -409,6 +416,7 @@ void displayio_display_background(displayio_display_obj_t* self) {
} }
void release_display(displayio_display_obj_t* self) { void release_display(displayio_display_obj_t* self) {
common_hal_displayio_display_set_auto_refresh(self, false);
release_display_core(&self->core); release_display_core(&self->core);
#if (CIRCUITPY_PULSEIO) #if (CIRCUITPY_PULSEIO)
if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { if (self->backlight_pwm.base.type == &pulseio_pwmout_type) {
@ -423,7 +431,7 @@ void release_display(displayio_display_obj_t* self) {
} }
void reset_display(displayio_display_obj_t* self) { void reset_display(displayio_display_obj_t* self) {
self->auto_refresh = true; common_hal_displayio_display_set_auto_refresh(self, true);
self->auto_brightness = true; self->auto_brightness = true;
common_hal_displayio_display_show(self, NULL); common_hal_displayio_display_show(self, NULL);
} }

View File

@ -187,6 +187,7 @@ void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self)
displayio_display_core_begin_transaction(&self->core); displayio_display_core_begin_transaction(&self->core);
self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &self->refresh_display_command, 1); self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &self->refresh_display_command, 1);
displayio_display_core_end_transaction(&self->core); displayio_display_core_end_transaction(&self->core);
supervisor_enable_tick();
self->refreshing = true; self->refreshing = true;
displayio_display_core_finish_refresh(&self->core); displayio_display_core_finish_refresh(&self->core);
@ -301,6 +302,7 @@ bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* s
if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) {
if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) {
supervisor_disable_tick();
self->refreshing = false; self->refreshing = false;
// Run stop sequence but don't wait for busy because busy is set when sleeping. // Run stop sequence but don't wait for busy because busy is set when sleeping.
send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len);
@ -342,6 +344,7 @@ void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) {
refresh_done = supervisor_ticks_ms64() - self->core.last_refresh > self->refresh_time; refresh_done = supervisor_ticks_ms64() - self->core.last_refresh > self->refresh_time;
} }
if (refresh_done) { if (refresh_done) {
supervisor_disable_tick();
self->refreshing = false; self->refreshing = false;
// Run stop sequence but don't wait for busy because busy is set when sleeping. // Run stop sequence but don't wait for busy because busy is set when sleeping.
send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len);
@ -352,6 +355,7 @@ void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) {
void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) {
if (self->refreshing) { if (self->refreshing) {
wait_for_busy(self); wait_for_busy(self);
supervisor_disable_tick();
self->refreshing = false; self->refreshing = false;
// Run stop sequence but don't wait for busy because busy is set when sleeping. // Run stop sequence but don't wait for busy because busy is set when sleeping.
send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len);

View File

@ -79,7 +79,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu
// Set the group after initialization otherwise we may send pixels while we delay in // Set the group after initialization otherwise we may send pixels while we delay in
// initialization. // initialization.
common_hal_framebufferio_framebufferdisplay_show(self, &circuitpython_splash); common_hal_framebufferio_framebufferdisplay_show(self, &circuitpython_splash);
self->auto_refresh = auto_refresh; common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, auto_refresh);
} }
bool common_hal_framebufferio_framebufferdisplay_show(framebufferio_framebufferdisplay_obj_t* self, displayio_group_t* root_group) { bool common_hal_framebufferio_framebufferdisplay_show(framebufferio_framebufferdisplay_obj_t* self, displayio_group_t* root_group) {
@ -280,6 +280,13 @@ bool common_hal_framebufferio_framebufferdisplay_get_auto_refresh(framebufferio_
void common_hal_framebufferio_framebufferdisplay_set_auto_refresh(framebufferio_framebufferdisplay_obj_t* self, void common_hal_framebufferio_framebufferdisplay_set_auto_refresh(framebufferio_framebufferdisplay_obj_t* self,
bool auto_refresh) { bool auto_refresh) {
self->first_manual_refresh = !auto_refresh; self->first_manual_refresh = !auto_refresh;
if (auto_refresh != self->auto_refresh) {
if (auto_refresh) {
supervisor_enable_tick();
} else {
supervisor_disable_tick();
}
}
self->auto_refresh = auto_refresh; self->auto_refresh = auto_refresh;
} }
@ -297,12 +304,13 @@ void framebufferio_framebufferdisplay_background(framebufferio_framebufferdispla
} }
void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) {
common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, false);
release_display_core(&self->core); release_display_core(&self->core);
self->framebuffer_protocol->deinit(self->framebuffer); self->framebuffer_protocol->deinit(self->framebuffer);
} }
void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) {
self->auto_refresh = true; common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true);
common_hal_framebufferio_framebufferdisplay_show(self, NULL); common_hal_framebufferio_framebufferdisplay_show(self, NULL);
} }

View File

@ -0,0 +1,87 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jeff Epler 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.
*/
#ifndef CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H
#define CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H
/** Background callbacks are a linked list of tasks to call in the background.
*
* Include a member of type `background_callback_t` inside an object
* which needs to queue up background work, and zero-initialize it.
*
* To schedule the work, use background_callback_add, with fun as the
* function to call and data pointing to the object itself.
*
* Next time run_background_tasks_if_tick is called, the callback will
* be run and removed from the linked list.
*
* Queueing a task that is already queued does nothing. Unconditionally
* re-queueing it from its own background task will cause it to run during the
* very next background-tasks invocation, leading to a CircuitPython freeze, so
* don't do that.
*
* background_callback_add can be called from interrupt context.
*/
typedef void (*background_callback_fun)(void *data);
typedef struct background_callback {
background_callback_fun fun;
void *data;
struct background_callback *next;
struct background_callback *prev;
} background_callback_t;
/* Add a background callback for which 'fun' and 'data' were previously set */
void background_callback_add_core(background_callback_t *cb);
/* Add a background callback to the given function with the given data. When
* the callback involves an object on the GC heap, the 'data' must be a pointer
* to that object itself, not an internal pointer. Otherwise, it can be the
* case that no other references to the object itself survive, and the object
* becomes garbage collected while an outstanding background callback still
* exists.
*/
void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data);
/* Run all background callbacks. Normally, this is done by the supervisor
* whenever the list is non-empty */
void background_callback_run_all(void);
/* During soft reset, remove all pending callbacks and clear the critical section flag */
void background_callback_reset(void);
/* Sometimes background callbacks must be blocked. Use these functions to
* bracket the section of code where this is the case. These calls nest, and
* begins must be balanced with ends.
*/
void background_callback_begin_critical_section(void);
void background_callback_end_critical_section(void);
/*
* Background callbacks may stop objects from being collected
*/
void background_callback_gc_collect(void);
#endif

View File

@ -91,4 +91,12 @@ void port_interrupt_after_ticks(uint32_t ticks);
// Sleep the CPU until an interrupt is received. // Sleep the CPU until an interrupt is received.
void port_sleep_until_interrupt(void); void port_sleep_until_interrupt(void);
// Execute port specific actions during background tasks.
void port_background_task(void);
// Take port specific actions at the beginning and end of background tasks.
// This is used e.g., to set a monitoring pin for debug purposes. "Actual
// work" should be done in port_background_task() instead.
void port_start_background_task(void);
void port_finish_background_task(void);
#endif // MICROPY_INCLUDED_SUPERVISOR_PORT_H #endif // MICROPY_INCLUDED_SUPERVISOR_PORT_H

View File

@ -0,0 +1,130 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jeff Epler 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/gc.h"
#include "py/mpconfig.h"
#include "supervisor/background_callback.h"
#include "supervisor/shared/tick.h"
#include "shared-bindings/microcontroller/__init__.h"
STATIC volatile background_callback_t *callback_head, *callback_tail;
#define CALLBACK_CRITICAL_BEGIN (common_hal_mcu_disable_interrupts())
#define CALLBACK_CRITICAL_END (common_hal_mcu_enable_interrupts())
void background_callback_add_core(background_callback_t *cb) {
CALLBACK_CRITICAL_BEGIN;
if (cb->prev || callback_head == cb) {
CALLBACK_CRITICAL_END;
return;
}
cb->next = 0;
cb->prev = (background_callback_t*)callback_tail;
if (callback_tail) {
callback_tail->next = cb;
cb->prev = (background_callback_t*)callback_tail;
}
if (!callback_head) {
callback_head = cb;
}
callback_tail = cb;
CALLBACK_CRITICAL_END;
}
void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data) {
cb->fun = fun;
cb->data = data;
background_callback_add_core(cb);
}
static bool in_background_callback;
void background_callback_run_all() {
if (!callback_head) {
return;
}
CALLBACK_CRITICAL_BEGIN;
if (in_background_callback) {
CALLBACK_CRITICAL_END;
return;
}
in_background_callback = true;
background_callback_t *cb = (background_callback_t*)callback_head;
callback_head = NULL;
callback_tail = NULL;
while (cb) {
background_callback_t *next = cb->next;
cb->next = cb->prev = NULL;
background_callback_fun fun = cb->fun;
void *data = cb->data;
CALLBACK_CRITICAL_END;
// Leave the critical section in order to run the callback function
if (fun) {
fun(data);
}
CALLBACK_CRITICAL_BEGIN;
cb = next;
}
in_background_callback = false;
CALLBACK_CRITICAL_END;
}
void background_callback_begin_critical_section() {
CALLBACK_CRITICAL_BEGIN;
}
void background_callback_end_critical_section() {
CALLBACK_CRITICAL_END;
}
void background_callback_reset() {
CALLBACK_CRITICAL_BEGIN;
callback_head = NULL;
callback_tail = NULL;
in_background_callback = false;
CALLBACK_CRITICAL_END;
}
void background_callback_gc_collect(void) {
// We don't enter the callback critical section here. We rely on
// gc_collect_ptr _NOT_ entering background callbacks, so it is not
// possible for the list to be cleared.
//
// However, it is possible for the list to be extended. We make the
// minor assumption that no newly added callback is for a
// collectable object. That is, we only plug the hole where an
// object becomes collectable AFTER it is added but before the
// callback is run, not the hole where an object was ALREADY
// collectable but adds a background task for itself.
//
// It's necessary to traverse the whole list here, as the callbacks
// themselves can be in non-gc memory, and some of the cb->data
// objects themselves might be in non-gc memory.
background_callback_t *cb = (background_callback_t*)callback_head;
while(cb) {
gc_collect_ptr(cb->data);
cb = cb->next;
}
}

View File

@ -29,10 +29,19 @@
#include "py/mpstate.h" #include "py/mpstate.h"
#include "supervisor/linker.h" #include "supervisor/linker.h"
#include "supervisor/filesystem.h" #include "supervisor/filesystem.h"
#include "supervisor/background_callback.h"
#include "supervisor/port.h" #include "supervisor/port.h"
#include "supervisor/shared/autoreload.h" #include "supervisor/shared/autoreload.h"
#include "supervisor/shared/stack.h"
static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks); #if CIRCUITPY_BLEIO
#include "supervisor/shared/bluetooth.h"
#include "common-hal/_bleio/bonding.h"
#endif
#if CIRCUITPY_DISPLAYIO
#include "shared-module/displayio/__init__.h"
#endif
#if CIRCUITPY_GAMEPAD #if CIRCUITPY_GAMEPAD
#include "shared-module/gamepad/__init__.h" #include "shared-module/gamepad/__init__.h"
@ -42,6 +51,10 @@ static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
#include "shared-module/gamepadshift/__init__.h" #include "shared-module/gamepadshift/__init__.h"
#endif #endif
#if CIRCUITPY_NETWORK
#include "shared-module/network/__init__.h"
#endif
#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/__init__.h"
#if CIRCUITPY_WATCHDOG #if CIRCUITPY_WATCHDOG
@ -51,6 +64,44 @@ static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
#define WATCHDOG_EXCEPTION_CHECK() 0 #define WATCHDOG_EXCEPTION_CHECK() 0
#endif #endif
static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
static background_callback_t callback;
volatile uint64_t last_finished_tick = 0;
void supervisor_background_tasks(void *unused) {
port_start_background_task();
assert_heap_ok();
#if CIRCUITPY_DISPLAYIO
displayio_background();
#endif
#if CIRCUITPY_NETWORK
network_module_background();
#endif
filesystem_background();
#if CIRCUITPY_BLEIO
supervisor_bluetooth_background();
bonding_background();
#endif
port_background_task();
assert_heap_ok();
last_finished_tick = port_get_raw_ticks(NULL);
port_finish_background_task();
}
bool supervisor_background_tasks_ok(void) {
return port_get_raw_ticks(NULL) - last_finished_tick < 1024;
}
void supervisor_tick(void) { void supervisor_tick(void) {
#if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0 #if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0
filesystem_tick(); filesystem_tick();
@ -68,6 +119,7 @@ void supervisor_tick(void) {
#endif #endif
} }
#endif #endif
background_callback_add(&callback, supervisor_background_tasks, NULL);
} }
uint64_t supervisor_ticks_ms64() { uint64_t supervisor_ticks_ms64() {
@ -83,14 +135,9 @@ uint32_t supervisor_ticks_ms32() {
return supervisor_ticks_ms64(); return supervisor_ticks_ms64();
} }
extern void run_background_tasks(void);
void PLACE_IN_ITCM(supervisor_run_background_tasks_if_tick)() { void PLACE_IN_ITCM(supervisor_run_background_tasks_if_tick)() {
// TODO: Add a global that can be set by anyone to indicate we should run background tasks. That background_callback_run_all();
// way we can short circuit the background tasks early. We used to do it based on time but it
// breaks cases where we wake up for a short period and then sleep. If we skipped the last
// background task or more before sleeping we may end up starving a task like USB.
run_background_tasks();
} }
void mp_hal_delay_ms(mp_uint_t delay) { void mp_hal_delay_ms(mp_uint_t delay) {
@ -104,13 +151,13 @@ void mp_hal_delay_ms(mp_uint_t delay) {
// Check to see if we've been CTRL-Ced by autoreload or the user. // Check to see if we've been CTRL-Ced by autoreload or the user.
if(MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) if(MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)))
{ {
// clear exception and generate stacktrace // clear exception and generate stacktrace
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
nlr_raise(&MP_STATE_VM(mp_kbd_exception)); nlr_raise(&MP_STATE_VM(mp_kbd_exception));
} }
if( MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception)) || if( MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception)) ||
WATCHDOG_EXCEPTION_CHECK()) { WATCHDOG_EXCEPTION_CHECK()) {
// stop sleeping immediately // stop sleeping immediately
break; break;
} }
remaining = end_tick - port_get_raw_ticks(NULL); remaining = end_tick - port_get_raw_ticks(NULL);

View File

@ -28,6 +28,7 @@
#define __INCLUDED_SUPERVISOR_TICK_H #define __INCLUDED_SUPERVISOR_TICK_H
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
/** @brief To be called once every ms /** @brief To be called once every ms
* *
@ -36,13 +37,6 @@
* interrupt context. * interrupt context.
*/ */
extern void supervisor_tick(void); extern void supervisor_tick(void);
/** @brief Cause background tasks to be called soon
*
* Normally, background tasks are only run once per tick. For other cases where
* an event noticed from an interrupt context needs to be completed by a background
* task activity, the interrupt can call supervisor_fake_tick.
*/
extern void supervisor_fake_tick(void);
/** @brief Get the lower 32 bits of the time in milliseconds /** @brief Get the lower 32 bits of the time in milliseconds
* *
* This can be more efficient than supervisor_ticks_ms64, for sites where a wraparound * This can be more efficient than supervisor_ticks_ms64, for sites where a wraparound
@ -67,4 +61,12 @@ extern void supervisor_run_background_if_tick(void);
extern void supervisor_enable_tick(void); extern void supervisor_enable_tick(void);
extern void supervisor_disable_tick(void); extern void supervisor_disable_tick(void);
/**
* @brief Return true if tick-based background tasks ran within the last 1s
*
* Note that when ticks are not enabled, this function can return false; this is
* intended.
*/
extern bool supervisor_background_tasks_ok(void);
#endif #endif

View File

@ -27,6 +27,7 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/Processor.h"
#include "shared-module/usb_midi/__init__.h" #include "shared-module/usb_midi/__init__.h"
#include "supervisor/background_callback.h"
#include "supervisor/port.h" #include "supervisor/port.h"
#include "supervisor/usb.h" #include "supervisor/usb.h"
#include "lib/utils/interrupt_char.h" #include "lib/utils/interrupt_char.h"
@ -82,6 +83,16 @@ void usb_background(void) {
} }
} }
static background_callback_t callback;
static void usb_background_do(void* unused) {
usb_background();
}
void usb_irq_handler(void) {
tud_int_handler(0);
background_callback_add(&callback, usb_background_do, NULL);
}
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// tinyusb callbacks // tinyusb callbacks
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+

View File

@ -2,6 +2,7 @@ SRC_SUPERVISOR = \
main.c \ main.c \
supervisor/port.c \ supervisor/port.c \
supervisor/shared/autoreload.c \ supervisor/shared/autoreload.c \
supervisor/shared/background_callback.c \
supervisor/shared/board.c \ supervisor/shared/board.c \
supervisor/shared/filesystem.c \ supervisor/shared/filesystem.c \
supervisor/shared/flash.c \ supervisor/shared/flash.c \

View File

@ -29,10 +29,15 @@
#include <stdbool.h> #include <stdbool.h>
// Ports must call this as frequently as they can in order to keep the USB connection // Ports must call this as frequently as they can in order to keep the USB
// alive and responsive. // connection alive and responsive. Normally this is called from background
// tasks after the USB IRQ handler is executed, but in specific circumstances
// it may be necessary to call it directly.
void usb_background(void); void usb_background(void);
// Ports must call this from their particular USB IRQ handler
void usb_irq_handler(void);
// Only inits the USB peripheral clocks and pins. The peripheral will be initialized by // Only inits the USB peripheral clocks and pins. The peripheral will be initialized by
// TinyUSB. // TinyUSB.
void init_usb_hardware(void); void init_usb_hardware(void);

View File

@ -0,0 +1,22 @@
import ujson as json
# Test that json can load from any object with readinto
class Buffer:
def __init__(self, data):
self._data = data
self._i = 0
def readinto(self, buf):
end = self._i + len(buf)
remaining = len(self._data) - self._i
end = min(end, len(self._data))
l = min(len(buf), remaining)
buf[:l] = self._data[self._i:end]
self._i += l
return l
print(json.load(Buffer(b'null')))
print(json.load(Buffer(b'"abc\\u0064e"')))
print(json.load(Buffer(b'[false, true, 1, -2]')))
print(json.load(Buffer(b'{"a":true}')))

View File

@ -0,0 +1,4 @@
None
abcde
[False, True, 1, -2]
{'a': True}