diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 50f73fc17010e..bc47f61829b89 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -149,7 +149,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input mp_hal_stdout_tx_strn("\x04", 1); } // check for SystemExit - if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { + if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // at the moment, the value of SystemExit is unused ret = pyexec_system_exit; #if CIRCUITPY_ALARM diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c index e03800f202eed..883fe0a192519 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -273,13 +273,13 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma, #ifdef SAM_D5X_E5X int irq = dma->event_channel < 4 ? EVSYS_0_IRQn + dma->event_channel : EVSYS_4_IRQn; + // Only disable and clear on SAMD51 because the SAMD21 shares EVSYS with ticks. + NVIC_DisableIRQ(irq); + NVIC_ClearPendingIRQ(irq); #else int irq = EVSYS_IRQn; #endif - NVIC_DisableIRQ(irq); - NVIC_ClearPendingIRQ(irq); - DmacDescriptor *first_descriptor = dma_descriptor(dma_channel); setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address); if (single_buffer) { @@ -374,7 +374,7 @@ STATIC void dma_callback_fun(void *arg) { audio_dma_load_next_block(dma); } -void evsyshandler_common(void) { +void audio_evsys_handler(void) { for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) { audio_dma_t *dma = audio_dma_state[i]; if (dma == NULL) { @@ -388,26 +388,4 @@ void evsyshandler_common(void) { } } -#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 diff --git a/ports/atmel-samd/audio_dma.h b/ports/atmel-samd/audio_dma.h index bc5beb3bf5c53..d06b5897590ec 100644 --- a/ports/atmel-samd/audio_dma.h +++ b/ports/atmel-samd/audio_dma.h @@ -99,4 +99,6 @@ void audio_dma_background(void); uint8_t find_sync_event_channel_raise(void); +void audio_evsys_handler(void); + #endif // MICROPY_INCLUDED_ATMEL_SAMD_AUDIO_DMA_H diff --git a/ports/atmel-samd/boards/adafruit_proxlight_trinkey_m0/mpconfigboard.h b/ports/atmel-samd/boards/adafruit_proxlight_trinkey_m0/mpconfigboard.h index c792b01272890..878b25f2f8c11 100644 --- a/ports/atmel-samd/boards/adafruit_proxlight_trinkey_m0/mpconfigboard.h +++ b/ports/atmel-samd/boards/adafruit_proxlight_trinkey_m0/mpconfigboard.h @@ -2,6 +2,7 @@ #define MICROPY_HW_MCU_NAME "samd21e18" #define MICROPY_HW_NEOPIXEL (&pin_PA15) +#define MICROPY_HW_NEOPIXEL_COUNT (2) #define IGNORE_PIN_PA01 1 #define IGNORE_PIN_PA02 1 diff --git a/ports/atmel-samd/boards/adafruit_proxlight_trinkey_m0/mpconfigboard.mk b/ports/atmel-samd/boards/adafruit_proxlight_trinkey_m0/mpconfigboard.mk index 3ef6dafac6b86..10a2f4ed379ad 100644 --- a/ports/atmel-samd/boards/adafruit_proxlight_trinkey_m0/mpconfigboard.mk +++ b/ports/atmel-samd/boards/adafruit_proxlight_trinkey_m0/mpconfigboard.mk @@ -14,6 +14,7 @@ CIRCUITPY_FULL_BUILD = 0 CIRCUITPY_ANALOGIO = 0 CIRCUITPY_AUDIOCORE = 0 CIRCUITPY_BUSIO_SPI = 0 +CIRCUITPY_BUSIO_UART = 0 CIRCUITPY_PULSEIO = 0 CIRCUITPY_PWMIO = 0 CIRCUITPY_ROTARYIO = 0 diff --git a/ports/atmel-samd/boards/arduino_mkr1300/mpconfigboard.h b/ports/atmel-samd/boards/arduino_mkr1300/mpconfigboard.h index f0748f35de015..6a3f7a96873cd 100644 --- a/ports/atmel-samd/boards/arduino_mkr1300/mpconfigboard.h +++ b/ports/atmel-samd/boards/arduino_mkr1300/mpconfigboard.h @@ -16,3 +16,16 @@ // USB is always used internally so skip the pin objects for it. #define IGNORE_PIN_PA24 1 #define IGNORE_PIN_PA25 1 +// USD ID +#define IGNORE_PIN_PA18 1 + +// Hooked to the external crystal +#define IGNORE_PIN_PA00 1 +#define IGNORE_PIN_PA01 1 + +// SWD only +#define IGNORE_PIN_PA30 1 +#define IGNORE_PIN_PA31 1 + +// Not connected +#define IGNORE_PIN_PA28 1 diff --git a/ports/atmel-samd/boards/arduino_nano_33_iot/mpconfigboard.h b/ports/atmel-samd/boards/arduino_nano_33_iot/mpconfigboard.h index 62883ad4a51d8..6be4f5606aefa 100644 --- a/ports/atmel-samd/boards/arduino_nano_33_iot/mpconfigboard.h +++ b/ports/atmel-samd/boards/arduino_nano_33_iot/mpconfigboard.h @@ -16,3 +16,11 @@ // USB is always used internally so skip the pin objects for it. #define IGNORE_PIN_PA24 1 #define IGNORE_PIN_PA25 1 + +// Not connected +#define IGNORE_PIN_PA00 1 +#define IGNORE_PIN_PA01 1 + +// SWD only +#define IGNORE_PIN_PA30 1 +#define IGNORE_PIN_PA31 1 diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c index 49cef924783c3..507db7e4372f1 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -272,6 +272,9 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t *self) { void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t *self) { uint32_t mask = 1 << self->channel; EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos; + #ifdef SAMD21 + rtc_end_pulse(); + #endif } void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t *self, @@ -299,6 +302,9 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t *self, EIC->INTFLAG.reg = mask << EIC_INTFLAG_EXTINT_Pos; EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos; + #ifdef SAMD21 + rtc_start_pulse(); + #endif pulsein_set_config(self, true); } diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index c03b79ce4f2e2..9ad54e5604cf4 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -91,26 +91,19 @@ #if CIRCUITPY_PEW #include "common-hal/_pew/PewPew.h" #endif -volatile bool hold_interrupt = false; +static volatile bool sleep_ok = true; #ifdef SAMD21 -static void rtc_set_continuous(bool continuous) { - while (RTC->MODE0.STATUS.bit.SYNCBUSY) { - ; - } - RTC->MODE0.READREQ.reg = (continuous ? RTC_READREQ_RCONT : 0) | 0x0010; - while (RTC->MODE0.STATUS.bit.SYNCBUSY) { - ; - } -} +static uint8_t _tick_event_channel = 0; +// Sleeping requires a register write that can stall interrupt handling. Turning +// off sleeps allows for more accurate interrupt timing. (Python still thinks +// it is sleeping though.) void rtc_start_pulse(void) { - rtc_set_continuous(true); - hold_interrupt = true; + sleep_ok = false; } void rtc_end_pulse(void) { - hold_interrupt = false; - rtc_set_continuous(false); + sleep_ok = true; } #endif @@ -161,6 +154,20 @@ static void save_usb_clock_calibration(void) { } #endif +static void rtc_continuous_mode(void) { + #ifdef SAMD21 + while (RTC->MODE0.STATUS.bit.SYNCBUSY) { + } + RTC->MODE0.READREQ.reg = RTC_READREQ_RCONT | 0x0010; + while (RTC->MODE0.STATUS.bit.SYNCBUSY) { + } + // Do the first request and wait for it. + RTC->MODE0.READREQ.reg = RTC_READREQ_RREQ | RTC_READREQ_RCONT | 0x0010; + while (RTC->MODE0.STATUS.bit.SYNCBUSY) { + } + #endif +} + static void rtc_init(void) { #ifdef SAMD21 _gclk_enable_channel(RTC_GCLK_ID, GCLK_CLKCTRL_GEN_GCLK2_Val); @@ -168,9 +175,17 @@ static void rtc_init(void) { while (RTC->MODE0.CTRL.bit.SWRST != 0) { } + // Turn on periodic events to use as tick. We control whether it interrupts + // us with the EVSYS INTEN register. + RTC->MODE0.EVCTRL.reg = RTC_MODE0_EVCTRL_PEREO2; + RTC->MODE0.CTRL.reg = RTC_MODE0_CTRL_ENABLE | RTC_MODE0_CTRL_MODE_COUNT32 | RTC_MODE0_CTRL_PRESCALER_DIV2; + + // Turn on continuous sync of the count register. This will speed up all + // tick reads. + rtc_continuous_mode(); #endif #ifdef SAM_D5X_E5X hri_mclk_set_APBAMASK_RTC_bit(MCLK); @@ -363,6 +378,9 @@ void reset_port(void) { #endif reset_event_system(); + #ifdef SAMD21 + _tick_event_channel = EVSYS_SYNCH_NUM; + #endif reset_all_pins(); @@ -430,21 +448,14 @@ uint32_t port_get_saved_word(void) { // TODO: Move this to an RTC backup register so we can preserve it when only the BACKUP power domain // is enabled. static volatile uint64_t overflowed_ticks = 0; -#ifdef SAMD21 -static volatile bool _ticks_enabled = false; -#endif static uint32_t _get_count(uint64_t *overflow_count) { #ifdef SAM_D5X_E5X while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COUNTSYNC | RTC_MODE0_SYNCBUSY_COUNT)) != 0) { } #endif - #ifdef SAMD21 - // Request a read so we don't stall the bus later. See section 14.3.1.5 Read Request - RTC->MODE0.READREQ.reg = RTC_READREQ_RREQ | 0x0010; - while (RTC->MODE0.STATUS.bit.SYNCBUSY != 0) { - } - #endif + // SAMD21 does continuous sync so we don't need to wait here. + // Disable interrupts so we can grab the count and the overflow. common_hal_mcu_disable_interrupts(); uint32_t count = RTC->MODE0.COUNT.reg; @@ -458,29 +469,6 @@ static uint32_t _get_count(uint64_t *overflow_count) { volatile bool _woken_up; -static void _port_interrupt_after_ticks(uint32_t ticks) { - uint32_t current_ticks = _get_count(NULL); - if (ticks > 1 << 28) { - // We'll interrupt sooner with an overflow. - return; - } - #ifdef SAMD21 - if (hold_interrupt) { - return; - } - #endif - uint32_t target = current_ticks + (ticks << 4); - RTC->MODE0.COMP[0].reg = target; - #ifdef SAM_D5X_E5X - while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP0)) != 0) { - } - #endif - RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; - RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; - current_ticks = _get_count(NULL); - _woken_up = current_ticks >= target; -} - void RTC_Handler(void) { uint32_t intflag = RTC->MODE0.INTFLAG.reg; if (intflag & RTC_MODE0_INTFLAG_OVF) { @@ -497,19 +485,10 @@ void RTC_Handler(void) { } #endif if (intflag & RTC_MODE0_INTFLAG_CMP0) { - // Clear the interrupt because we may have hit a sleep and _ticks_enabled + // Clear the interrupt because we may have hit a sleep RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; _woken_up = true; - #ifdef SAMD21 - if (_ticks_enabled) { - // Do things common to all ports when the tick occurs. - supervisor_tick(); - // Check _ticks_enabled again because a tick handler may have turned it off. - if (_ticks_enabled) { - _port_interrupt_after_ticks(1); - } - } - #endif + // SAMD21 ticks are handled by EVSYS #ifdef SAM_D5X_E5X RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0; #endif @@ -526,6 +505,39 @@ uint64_t port_get_raw_ticks(uint8_t *subticks) { return overflow_count + current_ticks / 16; } +void evsyshandler_common(void) { + #ifdef SAMD21 + if (_tick_event_channel < EVSYS_SYNCH_NUM && event_interrupt_active(_tick_event_channel)) { + supervisor_tick(); + } + #endif + #if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO + audio_evsys_handler(); + #endif +} + +#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 + // Enable 1/1024 second tick. void port_enable_tick(void) { #ifdef SAM_D5X_E5X @@ -533,9 +545,23 @@ void port_enable_tick(void) { RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_PER2; #endif #ifdef SAMD21 - // TODO: Switch to using the PER *event* from the RTC to generate an interrupt via EVSYS. - _ticks_enabled = true; - _port_interrupt_after_ticks(1); + // SAMD21 ticks won't survive port_reset(). This *should* be ok since it'll + // be triggered by ticks and no Python will be running. + if (_tick_event_channel >= EVSYS_SYNCH_NUM) { + turn_on_event_system(); + _tick_event_channel = find_sync_event_channel(); + } + // This turns on both the event detected interrupt (EVD) and overflow (OVR). + init_event_channel_interrupt(_tick_event_channel, CORE_GCLK, EVSYS_ID_GEN_RTC_PER_2); + // Disable overflow interrupt because we ignore it. + if (_tick_event_channel >= 8) { + uint8_t value = 1 << (_tick_event_channel - 8); + EVSYS->INTENCLR.reg = EVSYS_INTENSET_OVRp8(value); + } else { + uint8_t value = 1 << _tick_event_channel; + EVSYS->INTENCLR.reg = EVSYS_INTENSET_OVR(value); + } + NVIC_EnableIRQ(EVSYS_IRQn); #endif } @@ -545,21 +571,48 @@ void port_disable_tick(void) { RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_PER2; #endif #ifdef SAMD21 - _ticks_enabled = false; - RTC->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0; + if (_tick_event_channel >= 8) { + uint8_t value = 1 << (_tick_event_channel - 8); + EVSYS->INTENCLR.reg = EVSYS_INTENSET_EVDp8(value); + } else { + uint8_t value = 1 << _tick_event_channel; + EVSYS->INTENCLR.reg = EVSYS_INTENSET_EVD(value); + } #endif } -// This is called by sleep, we ignore it when our ticks are enabled because -// they'll wake us up earlier. If we don't, we'll mess up ticks by overwriting -// the next RTC wake up time. void port_interrupt_after_ticks(uint32_t ticks) { + uint32_t current_ticks = _get_count(NULL); + if (ticks > 1 << 28) { + // We'll interrupt sooner with an overflow. + return; + } #ifdef SAMD21 - if (_ticks_enabled) { + if (!sleep_ok) { return; } #endif - _port_interrupt_after_ticks(ticks); + + uint32_t target = current_ticks + (ticks << 4); + #ifdef SAMD21 + // Try and avoid a bus stall when writing COMP by checking for an obvious + // existing sync. + while (RTC->MODE0.STATUS.bit.SYNCBUSY == 1) { + } + #endif + // Writing the COMP register can take up to 180us to synchronize. During + // this time, the bus will stall and no interrupts will be serviced. + RTC->MODE0.COMP[0].reg = target; + #ifdef SAM_D5X_E5X + while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COMP0)) != 0) { + } + #endif + RTC->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; + RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; + // Set continuous mode again because setting COMP may disable it. + rtc_continuous_mode(); + current_ticks = _get_count(NULL); + _woken_up = current_ticks >= target; } void port_idle_until_interrupt(void) { @@ -571,7 +624,7 @@ void port_idle_until_interrupt(void) { } #endif common_hal_mcu_disable_interrupts(); - if (!tud_task_event_ready() && !hold_interrupt && !_woken_up) { + if (!tud_task_event_ready() && sleep_ok && !_woken_up) { __DSB(); __WFI(); } diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 4df9432efa308..be68904d18593 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -121,9 +121,15 @@ CFLAGS += -DCIRCUITPY_BUILTINS_POW3=$(CIRCUITPY_BUILTINS_POW3) CIRCUITPY_BUSIO ?= 1 CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO) +# These two flags pretend to implement their class but raise a ValueError due to +# unsupported pins. This should be used sparingly on boards that don't break out +# generic IO but need parts of busio. CIRCUITPY_BUSIO_SPI ?= 1 CFLAGS += -DCIRCUITPY_BUSIO_SPI=$(CIRCUITPY_BUSIO_SPI) +CIRCUITPY_BUSIO_UART ?= 1 +CFLAGS += -DCIRCUITPY_BUSIO_UART=$(CIRCUITPY_BUSIO_UART) + CIRCUITPY_CAMERA ?= 0 CFLAGS += -DCIRCUITPY_CAMERA=$(CIRCUITPY_CAMERA) @@ -184,7 +190,7 @@ CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO) CIRCUITPY_GAMEPADSHIFT ?= 0 CFLAGS += -DCIRCUITPY_GAMEPADSHIFT=$(CIRCUITPY_GAMEPADSHIFT) -CIRCUITPY_GETPASS ?= 1 +CIRCUITPY_GETPASS ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_GETPASS=$(CIRCUITPY_GETPASS) CIRCUITPY_GNSS ?= 0 @@ -330,7 +336,7 @@ CFLAGS += -DCIRCUITPY_TOUCHIO_USE_NATIVE=$(CIRCUITPY_TOUCHIO_USE_NATIVE) CIRCUITPY_TOUCHIO ?= 1 CFLAGS += -DCIRCUITPY_TOUCHIO=$(CIRCUITPY_TOUCHIO) -CIRCUITPY_TRACEBACK ?= 1 +CIRCUITPY_TRACEBACK ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_TRACEBACK=$(CIRCUITPY_TRACEBACK) # For debugging. diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 31f3a9021eac3..a611d8e1d581a 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -104,7 +104,7 @@ STATIC mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, con common_hal_busio_spi_construct(self, clock, mosi, miso); return MP_OBJ_FROM_PTR(self); #else - mp_raise_NotImplementedError(NULL); + mp_raise_ValueError(translate("Invalid pins")); #endif // CIRCUITPY_BUSIO_SPI } diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c index bd97910192343..efb0643d0b8e6 100644 --- a/shared-bindings/busio/UART.c +++ b/shared-bindings/busio/UART.c @@ -72,13 +72,16 @@ typedef struct { extern const busio_uart_parity_obj_t busio_uart_parity_even_obj; extern const busio_uart_parity_obj_t busio_uart_parity_odd_obj; +#if CIRCUITPY_BUSIO_UART STATIC void validate_timeout(mp_float_t timeout) { if (timeout < (mp_float_t)0.0f || timeout > (mp_float_t)100.0f) { mp_raise_ValueError(translate("timeout must be 0.0-100.0 seconds")); } } +#endif // CIRCUITPY_BUSIO_UART STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + #if CIRCUITPY_BUSIO_UART // Always initially allocate the UART object within the long-lived heap. // This is needed to avoid crashes with certain UART implementations which // cannot accomodate being moved after creation. (See @@ -141,8 +144,12 @@ STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, co args[ARG_baudrate].u_int, bits, parity, stop, timeout, args[ARG_receiver_buffer_size].u_int, NULL, false); return (mp_obj_t)self; + #else + mp_raise_ValueError(translate("Invalid pins")); + #endif // CIRCUITPY_BUSIO_UART } +#if CIRCUITPY_BUSIO_UART // Helper to ensure we have the native super class instead of a subclass. busio_uart_obj_t *native_uart(mp_obj_t uart_obj) { @@ -358,6 +365,7 @@ STATIC mp_obj_t busio_uart_obj_reset_input_buffer(mp_obj_t self_in) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_reset_input_buffer_obj, busio_uart_obj_reset_input_buffer); +#endif // CIRCUITPY_BUSIO_UART //| class Parity: //| """Enum-like class to define the parity used to verify correct data transfer.""" @@ -400,6 +408,7 @@ const mp_obj_type_t busio_uart_parity_type = { }; STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = { + #if CIRCUITPY_BUSIO_UART { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&busio_uart_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_uart_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, @@ -417,12 +426,14 @@ STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&busio_uart_baudrate_obj) }, { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&busio_uart_in_waiting_obj) }, { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&busio_uart_timeout_obj) }, + #endif // CIRCUITPY_BUSIO_UART // Nested Enum-like Classes. { MP_ROM_QSTR(MP_QSTR_Parity), MP_ROM_PTR(&busio_uart_parity_type) }, }; STATIC MP_DEFINE_CONST_DICT(busio_uart_locals_dict, busio_uart_locals_dict_table); +#if CIRCUITPY_BUSIO_UART STATIC const mp_stream_p_t uart_stream_p = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream) .read = busio_uart_read, @@ -445,3 +456,11 @@ const mp_obj_type_t busio_uart_type = { .protocol = &uart_stream_p, ), }; +#else +const mp_obj_type_t busio_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .make_new = busio_uart_make_new, + .locals_dict = (mp_obj_dict_t *)&busio_uart_locals_dict, +}; +#endif // CIRCUITPY_BUSIO_UART