diff --git a/main.c b/main.c index 91687ff2f8bc7..f4f67b0434787 100644 --- a/main.c +++ b/main.c @@ -43,6 +43,7 @@ #include "supervisor/shared/external_flash/external_flash.h" #include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/supervisor/__init__.h" #include "shared-bindings/supervisor/Runtime.h" @@ -124,6 +125,7 @@ static void reset_devices(void) { static uint8_t *_heap; static uint8_t *_pystack; +static volatile bool _vm_is_running = false; static const char line_clear[] = "\x1b[2K\x1b[0G"; @@ -207,9 +209,12 @@ static void start_mp(safe_mode_t safe_mode) { // Always return to root common_hal_os_chdir("/"); + + _vm_is_running = true; } static void stop_mp(void) { + _vm_is_running = false; #if MICROPY_VFS // Unmount all heap allocated vfs mounts. @@ -409,8 +414,13 @@ static void cleanup_after_vm(mp_obj_t exception) { // Free the heap last because other modules may reference heap memory and need to shut down. filesystem_flush(); + + // Runs finalisers while shutting down the heap. stop_mp(); + // Don't reset pins until finalisers have run. + reset_all_pins(); + // Let the workflows know we've reset in case they want to restart. supervisor_workflow_reset(); } @@ -513,6 +523,7 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s // Finished executing python code. Cleanup includes filesystem flush and a board reset. + _vm_is_running = false; cleanup_after_vm(_exec_result.exception); _exec_result.exception = NULL; @@ -1201,6 +1212,10 @@ void NORETURN nlr_jump_fail(void *val) { } } +bool vm_is_running(void) { + return _vm_is_running; +} + #ifndef NDEBUG static void NORETURN __fatal_error(const char *msg) { #if CIRCUITPY_DEBUG == 0 diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index b4a519c37a72d..de3856b23b3f1 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -42,7 +42,6 @@ typedef enum { SPI_FREE = 0, SPI_BUSY, - SPI_NEVER_RESET, } spi_status_t; // Set each bit to indicate an active SPI @@ -61,6 +60,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Check for NULL Pointer assert(self); + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + // Assign SPI ID based on pins int spi_id = pinsToSpi(mosi, miso, sck); if (spi_id == -1) { @@ -118,8 +120,6 @@ void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { common_hal_never_reset_pin(self->miso); common_hal_never_reset_pin(self->sck); common_hal_never_reset_pin(self->nss); - - spi_status[self->spi_id] = SPI_NEVER_RESET; } // Check SPI status, deinited or not @@ -127,6 +127,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->sck == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->sck = NULL; +} + // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { @@ -138,8 +142,9 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { self->mosi = NULL; self->miso = NULL; - self->sck = NULL; self->nss = NULL; + + common_hal_busio_spi_mark_deinit(self); } // Configures the SPI bus. The SPI object must be locked. diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index 40e8e1d605038..86d96bc251ba2 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -166,7 +166,6 @@ void reset_cpu(void) { // Reset MCU state void reset_port(void) { - reset_all_pins(); } // Reset to the bootloader diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index 5dd7bedebc394..fe53580afdf23 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -53,7 +53,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } // Ensure the object starts in its deinit state. - self->clock_pin = NO_PIN; + common_hal_busio_spi_mark_deinit(self); // Special case for SAMR21 boards. (feather_radiofruit_zigbee) #if defined(PIN_PC19F_SERCOM4_PAD0) @@ -184,18 +184,24 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock_pin == NO_PIN; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock_pin = NO_PIN; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } allow_reset_sercom(self->spi_desc.dev.prvt); + // Mark as deinit early in case we are used in an interrupt. + common_hal_busio_spi_mark_deinit(self); + spi_m_sync_disable(&self->spi_desc); spi_m_sync_deinit(&self->spi_desc); reset_pin_number(self->clock_pin); reset_pin_number(self->MOSI_pin); reset_pin_number(self->MISO_pin); - self->clock_pin = NO_PIN; } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 03c2c2543a7a7..9654a791dbb32 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -411,8 +411,6 @@ void reset_port(void) { reset_ticks(); } - reset_all_pins(); - // Output clocks for debugging. // not supported by SAMD51G; uncomment for SAMD51J or update for 51G // #ifdef SAM_D5X_E5X diff --git a/ports/broadcom/common-hal/busio/SPI.c b/ports/broadcom/common-hal/busio/SPI.c index 2396a9b921ee2..9e4834e86f352 100644 --- a/ports/broadcom/common-hal/busio/SPI.c +++ b/ports/broadcom/common-hal/busio/SPI.c @@ -30,31 +30,8 @@ static SPI0_Type *spi[NUM_SPI] = {SPI0, NULL, NULL}; static SPI1_Type *aux_spi[NUM_SPI] = {NULL, SPI1, SPI2}; #endif -static bool never_reset_spi[NUM_SPI]; static bool spi_in_use[NUM_SPI]; -void reset_spi(void) { - for (size_t i = 0; i < NUM_SPI; i++) { - if (never_reset_spi[i]) { - continue; - } - - if (i == 1 || i == 2) { - if (i == 1) { - AUX->ENABLES_b.SPI_1 = false; - } else { - AUX->ENABLES_b.SPI_2 = false; - } - aux_spi[i]->CNTL0 = 0; - } else { - // Set CS back to default. All 0 except read enable. - spi[i]->CS = SPI0_CS_REN_Msk; - } - - spi_in_use[i] = false; - } -} - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { @@ -67,6 +44,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError(MP_ERROR_TEXT("Half duplex SPI is not implemented")); } + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + // BCM_VERSION != 2711 have 3 SPI but as listed in peripherals/gen/pins.c two are on // index 0, once one index 0 SPI is found the other will throw an invalid_pins error. for (size_t i = 0; i < NUM_SPI; i++) { @@ -118,8 +98,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[self->index] = true; - common_hal_never_reset_pin(self->clock); common_hal_never_reset_pin(self->MOSI); common_hal_never_reset_pin(self->MISO); @@ -129,16 +107,19 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } - never_reset_spi[self->index] = false; common_hal_reset_pin(self->clock); common_hal_reset_pin(self->MOSI); common_hal_reset_pin(self->MISO); - self->clock = NULL; + spi_in_use[self->index] = false; if (self->index == 1 || @@ -149,7 +130,12 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } else if (self->index == 2) { AUX->ENABLES_b.SPI_2 = false; } + } else { + // Set CS back to default. All 0 except read enable. + spi[self->index]->CS = SPI0_CS_REN_Msk; } + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/broadcom/common-hal/busio/SPI.h b/ports/broadcom/common-hal/busio/SPI.h index aec91263677c0..3d52b6b0a4488 100644 --- a/ports/broadcom/common-hal/busio/SPI.h +++ b/ports/broadcom/common-hal/busio/SPI.h @@ -23,5 +23,3 @@ typedef struct { uint8_t bits; uint8_t index; } busio_spi_obj_t; - -void reset_spi(void); diff --git a/ports/broadcom/supervisor/port.c b/ports/broadcom/supervisor/port.c index 83dd50f1b8b52..a0f0be30dd758 100644 --- a/ports/broadcom/supervisor/port.c +++ b/ports/broadcom/supervisor/port.c @@ -67,7 +67,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO reset_i2c(); - reset_spi(); reset_uart(); #endif @@ -85,8 +84,6 @@ void reset_port(void) { #if CIRCUITPY_AUDIOCORE audio_dma_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/cxd56/common-hal/busio/SPI.c b/ports/cxd56/common-hal/busio/SPI.c index 8eedb624201dd..6c49e0f275066 100644 --- a/ports/cxd56/common-hal/busio/SPI.c +++ b/ports/cxd56/common-hal/busio/SPI.c @@ -54,7 +54,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { return; } - self->spi_dev = NULL; + common_hal_busio_spi_mark_deinit(self); reset_pin_number(self->clock_pin->number); reset_pin_number(self->mosi_pin->number); @@ -65,6 +65,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->spi_dev == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->spi_dev = NULL; +} + bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { uint8_t mode; diff --git a/ports/cxd56/supervisor/port.c b/ports/cxd56/supervisor/port.c index 75abcbf6d93e0..3dc54df96fbb5 100644 --- a/ports/cxd56/supervisor/port.c +++ b/ports/cxd56/supervisor/port.c @@ -66,8 +66,6 @@ void reset_port(void) { #if CIRCUITPY_RTC rtc_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index 98c453ba3c086..9ef3877ea92ed 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -128,6 +128,11 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { i2c_del_master_bus(self->handle); self->handle = NULL; + // Release the mutex before we delete it. Otherwise FreeRTOS gets unhappy. + xSemaphoreGive(self->xSemaphore); + vSemaphoreDelete(self->xSemaphore); + self->xSemaphore = NULL; + common_hal_reset_pin(self->sda_pin); common_hal_reset_pin(self->scl_pin); common_hal_busio_i2c_mark_deinit(self); diff --git a/ports/espressif/common-hal/busio/SPI.c b/ports/espressif/common-hal/busio/SPI.c index 6439ca4112993..4c07917b20b86 100644 --- a/ports/espressif/common-hal/busio/SPI.c +++ b/ports/espressif/common-hal/busio/SPI.c @@ -16,26 +16,12 @@ #define SPI_MAX_DMA_BITS (SPI_MAX_DMA_LEN * 8) #define MAX_SPI_TRANSACTIONS 10 -static bool spi_never_reset[SOC_SPI_PERIPH_NUM]; static spi_device_handle_t spi_handle[SOC_SPI_PERIPH_NUM]; -static StaticSemaphore_t spi_mutex[SOC_SPI_PERIPH_NUM]; static bool spi_bus_is_free(spi_host_device_t host_id) { return spi_bus_get_attr(host_id) == NULL; } -void spi_reset(void) { - for (spi_host_device_t host_id = SPI2_HOST; host_id < SOC_SPI_PERIPH_NUM; host_id++) { - if (spi_never_reset[host_id]) { - continue; - } - if (!spi_bus_is_free(host_id)) { - spi_bus_remove_device(spi_handle[host_id]); - spi_bus_free(host_id); - } - } -} - static void set_spi_config(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { // 128 is a 50% duty cycle. @@ -61,6 +47,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + const spi_bus_config_t bus_config = { .mosi_io_num = mosi != NULL ? mosi->number : -1, .miso_io_num = miso != NULL ? miso->number : -1, @@ -83,6 +72,11 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("All SPI peripherals are in use")); } + self->mutex = xSemaphoreCreateMutex(); + if (self->mutex == NULL) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to create lock")); + } + esp_err_t result = spi_bus_initialize(self->host_id, &bus_config, SPI_DMA_CH_AUTO); if (result == ESP_ERR_NO_MEM) { mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("ESP-IDF memory allocation failed")); @@ -90,6 +84,12 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, raise_ValueError_invalid_pins(); } + self->mutex = xSemaphoreCreateMutex(); + if (self->mutex == NULL) { + spi_bus_free(self->host_id); + mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to create lock")); + } + set_spi_config(self, 250000, 0, 0, 8); self->MOSI = mosi; @@ -103,12 +103,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, claim_pin(miso); } claim_pin(clock); - - self->mutex = xSemaphoreCreateMutexStatic(&spi_mutex[self->host_id]); } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - spi_never_reset[self->host_id] = true; common_hal_never_reset_pin(self->clock); if (self->MOSI != NULL) { common_hal_never_reset_pin(self->MOSI); @@ -122,6 +119,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -132,11 +133,10 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { RUN_BACKGROUND_TASKS; } - // Mark us as deinit early in case we are used in an interrupt. + // Mark as deinit early in case we are used in an interrupt. common_hal_reset_pin(self->clock); - self->clock = NULL; + common_hal_busio_spi_mark_deinit(self); - spi_never_reset[self->host_id] = false; spi_bus_remove_device(spi_handle[self->host_id]); spi_bus_free(self->host_id); @@ -170,11 +170,13 @@ bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { } bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { - return self->mutex != NULL && xSemaphoreGetMutexHolder(self->mutex) == xTaskGetCurrentTaskHandle(); + return (self->mutex != NULL) && (xSemaphoreGetMutexHolder(self->mutex) == xTaskGetCurrentTaskHandle()); } void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { - xSemaphoreGive(self->mutex); + if (self->mutex != NULL) { + xSemaphoreGive(self->mutex); + } } bool common_hal_busio_spi_write(busio_spi_obj_t *self, diff --git a/ports/espressif/common-hal/busio/SPI.h b/ports/espressif/common-hal/busio/SPI.h index 820f29333c756..ac2f404042b2f 100644 --- a/ports/espressif/common-hal/busio/SPI.h +++ b/ports/espressif/common-hal/busio/SPI.h @@ -25,5 +25,3 @@ typedef struct { SemaphoreHandle_t mutex; } busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 72c92c98baea2..c629eb52932e7 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -356,14 +356,11 @@ void reset_port(void) { ssl_reset(); #endif - reset_all_pins(); - #if CIRCUITPY_ANALOGIO analogout_reset(); #endif #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif diff --git a/ports/litex/common-hal/microcontroller/Pin.c b/ports/litex/common-hal/microcontroller/Pin.c index dea848f1ec3f3..bb3636c5b3faa 100644 --- a/ports/litex/common-hal/microcontroller/Pin.c +++ b/ports/litex/common-hal/microcontroller/Pin.c @@ -11,6 +11,10 @@ static uint8_t claimed_pins[1]; +void reset_all_pins(void) { + // TODO +} + // Mark pin as free and return it to a quiescent state. void reset_pin_number(uint8_t pin_port, uint8_t pin_number) { if (pin_port == 0x0F) { diff --git a/ports/litex/supervisor/port.c b/ports/litex/supervisor/port.c index 98fce16152e0b..7f9aab7f7ffb4 100644 --- a/ports/litex/supervisor/port.c +++ b/ports/litex/supervisor/port.c @@ -59,7 +59,6 @@ extern uint32_t _heap_start; extern uint32_t _estack; void reset_port(void) { - // reset_all_pins(); // i2c_reset(); // spi_reset(); // uart_reset(); diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.c b/ports/mimxrt10xx/common-hal/busio/SPI.c index 732b23d8c9b3b..90695be4b4e6d 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.c +++ b/ports/mimxrt10xx/common-hal/busio/SPI.c @@ -26,7 +26,6 @@ // arrays use 0 based numbering: SPI1 is stored at index 0 static bool reserved_spi[MP_ARRAY_SIZE(mcu_spi_banks)]; -static bool never_reset_spi[MP_ARRAY_SIZE(mcu_spi_banks)]; #if IMXRT11XX static const clock_ip_name_t s_lpspiClocks[] = LPSPI_CLOCKS; @@ -53,22 +52,6 @@ static void config_periph_pin(const mcu_periph_obj_t *periph) { | IOMUXC_SW_PAD_CTL_PAD_SRE(0)); } -void spi_reset(void) { - for (uint i = 0; i < MP_ARRAY_SIZE(mcu_spi_banks); i++) { - if (!never_reset_spi[i]) { - reserved_spi[i] = false; - #if IMXRT11XX - // Skip resetting SPIs that aren't clocked. Doing so generates a bus fault. - if ((CCM->LPCG[s_lpspiClocks[i + 1]].STATUS0 & CCM_LPCG_STATUS0_ON_MASK) == ((uint32_t)kCLOCK_Off & CCM_LPCG_STATUS0_ON_MASK)) { - continue; - } - #endif - - LPSPI_Deinit(mcu_spi_banks[i]); - } - } -} - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { @@ -82,6 +65,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); } + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + for (uint i = 0; i < sck_count; i++) { if (mcu_spi_sck_list[i].pin != clock) { continue; @@ -200,7 +186,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[self->clock->bank_idx - 1] = true; common_hal_never_reset_pin(self->clock->pin); if (self->mosi != NULL) { common_hal_never_reset_pin(self->mosi->pin); @@ -214,21 +199,25 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } LPSPI_Deinit(self->spi); reserved_spi[self->clock->bank_idx - 1] = false; - never_reset_spi[self->clock->bank_idx - 1] = false; common_hal_reset_pin(self->clock->pin); common_hal_reset_pin(self->mosi->pin); common_hal_reset_pin(self->miso->pin); - self->clock = NULL; self->mosi = NULL; self->miso = NULL; + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.h b/ports/mimxrt10xx/common-hal/busio/SPI.h index 67801078261c1..d86489428ec78 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.h +++ b/ports/mimxrt10xx/common-hal/busio/SPI.h @@ -21,5 +21,3 @@ typedef struct { const mcu_periph_obj_t *mosi; const mcu_periph_obj_t *miso; } busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/mimxrt10xx/supervisor/port.c b/ports/mimxrt10xx/supervisor/port.c index d7f7f280d1958..62d2569cfde4f 100644 --- a/ports/mimxrt10xx/supervisor/port.c +++ b/ports/mimxrt10xx/supervisor/port.c @@ -425,10 +425,6 @@ safe_mode_t port_init(void) { } void reset_port(void) { - #if CIRCUITPY_BUSIO - spi_reset(); - #endif - #if CIRCUITPY_AUDIOIO audio_dma_reset(); #endif @@ -450,8 +446,6 @@ void reset_port(void) { #endif // reset_event_system(); - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/nordic/common-hal/busio/SPI.c b/ports/nordic/common-hal/busio/SPI.c index 8af4c5f4e83f1..de54dd08a2783 100644 --- a/ports/nordic/common-hal/busio/SPI.c +++ b/ports/nordic/common-hal/busio/SPI.c @@ -59,26 +59,13 @@ static const spim_peripheral_t spim_peripherals[] = { #endif }; -static bool never_reset[MP_ARRAY_SIZE(spim_peripherals)]; - // Separate RAM area for SPIM3 transmit buffer to avoid SPIM3 hardware errata. // https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52840_Rev2%2FERR%2FnRF52840%2FRev2%2Flatest%2Fanomaly_840_198.html static uint8_t *spim3_transmit_buffer = (uint8_t *)SPIM3_BUFFER_RAM_START_ADDR; -void spi_reset(void) { - for (size_t i = 0; i < MP_ARRAY_SIZE(spim_peripherals); i++) { - if (never_reset[i]) { - continue; - } - nrfx_spim_uninit(&spim_peripherals[i].spim); - } -} - void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { for (size_t i = 0; i < MP_ARRAY_SIZE(spim_peripherals); i++) { if (self->spim_peripheral == &spim_peripherals[i]) { - never_reset[i] = true; - never_reset_pin_number(self->clock_pin_number); never_reset_pin_number(self->MOSI_pin_number); never_reset_pin_number(self->MISO_pin_number); @@ -125,6 +112,9 @@ static nrf_spim_frequency_t baudrate_to_spim_frequency(const uint32_t baudrate) void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + if (half_duplex) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); } @@ -178,6 +168,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock_pin_number == NO_PIN; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock_pin_number = NO_PIN; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -188,6 +182,8 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { reset_pin_number(self->clock_pin_number); reset_pin_number(self->MOSI_pin_number); reset_pin_number(self->MISO_pin_number); + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { diff --git a/ports/nordic/common-hal/busio/SPI.h b/ports/nordic/common-hal/busio/SPI.h index 7bfddd9625dcb..3260c5c27dee2 100644 --- a/ports/nordic/common-hal/busio/SPI.h +++ b/ports/nordic/common-hal/busio/SPI.h @@ -23,5 +23,3 @@ typedef struct { uint8_t MOSI_pin_number; uint8_t MISO_pin_number; } busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/nordic/supervisor/port.c b/ports/nordic/supervisor/port.c index ed371c6ad8582..1eabfcbe2166b 100644 --- a/ports/nordic/supervisor/port.c +++ b/ports/nordic/supervisor/port.c @@ -189,7 +189,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif @@ -216,8 +215,6 @@ void reset_port(void) { nrfx_gpiote_uninit(); } nrfx_gpiote_init(NRFX_GPIOTE_CONFIG_IRQ_PRIORITY); - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/raspberrypi/common-hal/busio/SPI.c b/ports/raspberrypi/common-hal/busio/SPI.c index 4735d1284f98e..aeb06d919ae45 100644 --- a/ports/raspberrypi/common-hal/busio/SPI.c +++ b/ports/raspberrypi/common-hal/busio/SPI.c @@ -19,24 +19,14 @@ #define NO_INSTANCE 0xff -static bool never_reset_spi[2]; -static spi_inst_t *spi[2] = {spi0, spi1}; - -void reset_spi(void) { - for (size_t i = 0; i < 2; i++) { - if (never_reset_spi[i]) { - continue; - } - - spi_deinit(spi[i]); - } -} - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { size_t instance_index = NO_INSTANCE; + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + if (half_duplex) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); } @@ -96,8 +86,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[spi_get_index(self->peripheral)] = true; - common_hal_never_reset_pin(self->clock); common_hal_never_reset_pin(self->MOSI); common_hal_never_reset_pin(self->MISO); @@ -107,17 +95,21 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } - never_reset_spi[spi_get_index(self->peripheral)] = false; spi_deinit(self->peripheral); common_hal_reset_pin(self->clock); common_hal_reset_pin(self->MOSI); common_hal_reset_pin(self->MISO); - self->clock = NULL; + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/raspberrypi/common-hal/busio/SPI.h b/ports/raspberrypi/common-hal/busio/SPI.h index 8510eb7693ae2..3d43c1eff0072 100644 --- a/ports/raspberrypi/common-hal/busio/SPI.h +++ b/ports/raspberrypi/common-hal/busio/SPI.h @@ -25,5 +25,3 @@ typedef struct { uint8_t phase; uint8_t bits; } busio_spi_obj_t; - -void reset_spi(void); diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 66e63248c4810..5cfbdfa66a32b 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -422,7 +422,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO - reset_spi(); reset_uart(); #endif @@ -453,8 +452,6 @@ void reset_port(void) { #if CIRCUITPY_WIFI wifi_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/renode/common-hal/busio/SPI.c b/ports/renode/common-hal/busio/SPI.c index 6f5f60506074f..1f66fc5ec4af1 100644 --- a/ports/renode/common-hal/busio/SPI.c +++ b/ports/renode/common-hal/busio/SPI.c @@ -21,6 +21,9 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return true; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; diff --git a/ports/silabs/common-hal/busio/SPI.c b/ports/silabs/common-hal/busio/SPI.c index 74cfc69bfb2a0..fb3b7c4fd20c7 100644 --- a/ports/silabs/common-hal/busio/SPI.c +++ b/ports/silabs/common-hal/busio/SPI.c @@ -37,16 +37,6 @@ static SPIDRV_HandleData_t spidrv_eusart_handle; static SPIDRV_Init_t spidrv_eusart_init = SPIDRV_MASTER_EUSART1; static bool in_used = false; -static bool never_reset = false; - -// Reset SPI when reload -void spi_reset(void) { - if (!never_reset && in_used) { - SPIDRV_DeInit(&spidrv_eusart_handle); - in_used = false; - } - return; -} // Construct SPI protocol, this function init SPI peripheral void common_hal_busio_spi_construct(busio_spi_obj_t *self, @@ -61,6 +51,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, MP_ERROR_TEXT("Half duplex SPI is not implemented")); } + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + if ((sck != NULL) && (mosi != NULL) && (miso != NULL)) { if (sck->function_list[FN_EUSART1_SCLK] == 1 && miso->function_list[FN_EUSART1_RX] == 1 @@ -108,7 +101,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Never reset SPI when reload void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset = true; common_hal_never_reset_pin(self->mosi); common_hal_never_reset_pin(self->miso); common_hal_never_reset_pin(self->sck); @@ -119,6 +111,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->sck == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->sck = NULL; +} + // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { @@ -132,13 +128,14 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } in_used = false; - self->sck = NULL; self->mosi = NULL; self->miso = NULL; self->handle = NULL; common_hal_reset_pin(self->mosi); common_hal_reset_pin(self->miso); common_hal_reset_pin(self->sck); + + common_hal_busio_spi_mark_deinit(self); } // Configures the SPI bus. The SPI object must be locked. diff --git a/ports/silabs/supervisor/port.c b/ports/silabs/supervisor/port.c index 2409e907deac1..85a6e0f92a5ec 100644 --- a/ports/silabs/supervisor/port.c +++ b/ports/silabs/supervisor/port.c @@ -156,10 +156,7 @@ safe_mode_t port_init(void) { } void reset_port(void) { - reset_all_pins(); - #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif diff --git a/ports/stm/common-hal/busio/SPI.c b/ports/stm/common-hal/busio/SPI.c index 98696271ca93a..1b86a9f55d5d4 100644 --- a/ports/stm/common-hal/busio/SPI.c +++ b/ports/stm/common-hal/busio/SPI.c @@ -19,7 +19,6 @@ #define MAX_SPI 6 static bool reserved_spi[MAX_SPI]; -static bool never_reset_spi[MAX_SPI]; #define ALL_CLOCKS 0xFF static void spi_clock_enable(uint8_t mask); @@ -76,18 +75,6 @@ static uint32_t stm32_baud_to_spi_div(uint32_t baudrate, uint16_t *prescaler, ui return SPI_BAUDRATEPRESCALER_256; } -void spi_reset(void) { - uint16_t never_reset_mask = 0x00; - for (int i = 0; i < MAX_SPI; i++) { - if (!never_reset_spi[i]) { - reserved_spi[i] = false; - } else { - never_reset_mask |= 1 << i; - } - } - spi_clock_disable(ALL_CLOCKS & ~(never_reset_mask)); -} - static const mcu_periph_obj_t *find_pin_function(const mcu_periph_obj_t *table, size_t sz, const mcu_pin_obj_t *pin, int periph_index) { for (size_t i = 0; i < sz; i++, table++) { if (periph_index == table->periph_index && pin == table->pin) { @@ -152,6 +139,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, int periph_index = check_pins(self, sck, mosi, miso); SPI_TypeDef *SPIx = mcu_spi_banks[periph_index - 1]; + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + // Start GPIO for each pin GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = pin_mask(sck->number); @@ -224,7 +214,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[self->sck->periph_index - 1] = true; never_reset_pin_number(self->sck->pin->port, self->sck->pin->number); if (self->mosi != NULL) { never_reset_pin_number(self->mosi->pin->port, self->mosi->pin->number); @@ -238,13 +227,16 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->sck == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->sck = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } spi_clock_disable(1 << (self->sck->periph_index - 1)); reserved_spi[self->sck->periph_index - 1] = false; - never_reset_spi[self->sck->periph_index - 1] = false; reset_pin_number(self->sck->pin->port, self->sck->pin->number); if (self->mosi != NULL) { diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index c5a1685a7fddc..3820a046fc4af 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -302,14 +302,11 @@ void SysTick_Handler(void) { } void reset_port(void) { - reset_all_pins(); - #if CIRCUITPY_RTC rtc_reset(); #endif #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif #if CIRCUITPY_SDIOIO diff --git a/py/mpstate.h b/py/mpstate.h index 4c48e9edaf4bd..e5e5f8d9fa3d1 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -369,4 +369,7 @@ extern mp_state_thread_t *mp_thread_get_state(void); #define mp_thread_is_main_thread() (true) #endif +// CIRCUITPY-CHANGE: defined in main.c +bool vm_is_running(void); + #endif // MICROPY_INCLUDED_PY_MPSTATE_H diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 0c8ae1bfdd72c..1513a7cf0944a 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -88,7 +88,7 @@ // TODO(tannewt): Support LSB SPI. static mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_BUSIO_SPI - busio_spi_obj_t *self = mp_obj_malloc(busio_spi_obj_t, &busio_spi_type); + busio_spi_obj_t *self = mp_obj_malloc_with_finaliser(busio_spi_obj_t, &busio_spi_type); enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -466,6 +466,7 @@ MP_PROPERTY_GETTER(busio_spi_frequency_obj, static const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { #if CIRCUITPY_BUSIO_SPI { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&busio_spi_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h index 69e582411a169..34f34c927f613 100644 --- a/shared-bindings/busio/SPI.h +++ b/shared-bindings/busio/SPI.h @@ -22,6 +22,10 @@ extern void common_hal_busio_spi_construct(busio_spi_obj_t *self, extern void common_hal_busio_spi_deinit(busio_spi_obj_t *self); extern bool common_hal_busio_spi_deinited(busio_spi_obj_t *self); +// Mark as deinit without deiniting. This is used by displayio after copying the +// object elsewhere and prevents the heap from deiniting the object. +extern void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self); + extern bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits); extern bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self); diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index e6d8453eae108..26892a79462d3 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -9,7 +9,8 @@ #include "py/objarray.h" #include "shared-bindings/sdcardio/SDCard.h" -#include "shared-module/sdcardio/SDCard.h" +#include "shared-bindings/util.h" + #include "common-hal/busio/SPI.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/microcontroller/Pin.h" @@ -58,6 +59,12 @@ //| os.listdir('/sd')""" //| +static void check_for_deinit(sdcardio_sdcard_obj_t *self) { + if (common_hal_sdcardio_sdcard_deinited(self)) { + raise_deinited_error(); + } +} + static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_spi, ARG_cs, ARG_baudrate, NUM_ARGS }; static const mp_arg_t allowed_args[] = { @@ -72,7 +79,7 @@ static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_arg busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj, MP_QSTR_spi); const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); - sdcardio_sdcard_obj_t *self = mp_obj_malloc(sdcardio_sdcard_obj_t, &sdcardio_SDCard_type); + sdcardio_sdcard_obj_t *self = mp_obj_malloc_with_finaliser(sdcardio_sdcard_obj_t, &sdcardio_SDCard_type); common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int); @@ -89,6 +96,7 @@ static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_arg //| static mp_obj_t sdcardio_sdcard_count(mp_obj_t self_in) { sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); return mp_obj_new_int_from_ull(common_hal_sdcardio_sdcard_get_blockcount(self)); } MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_count_obj, sdcardio_sdcard_count); @@ -116,10 +124,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_deinit_obj, sdcardio_sdcard_deinit); //| static mp_obj_t _sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); + uint32_t start_block = mp_obj_get_int(start_block_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; int result = common_hal_sdcardio_sdcard_readblocks(self, start_block, &bufinfo); if (result < 0) { mp_raise_OSError(-result); @@ -137,6 +147,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, _sdcardio_sdcard_readb //| static mp_obj_t sdcardio_sdcard_sync(mp_obj_t self_in) { sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); int result = common_hal_sdcardio_sdcard_sync(self); if (result < 0) { mp_raise_OSError(-result); @@ -158,10 +169,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_sync_obj, sdcardio_sdcard_sync); //| static mp_obj_t _sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); + uint32_t start_block = mp_obj_get_int(start_block_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; int result = common_hal_sdcardio_sdcard_writeblocks(self, start_block, &bufinfo); if (result < 0) { mp_raise_OSError(-result); @@ -173,6 +186,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, _sdcardio_sdcard_writ static const mp_rom_map_elem_t sdcardio_sdcard_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdcardio_sdcard_count_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdcardio_sdcard_readblocks_obj) }, { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&sdcardio_sdcard_sync_obj) }, { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdcardio_sdcard_writeblocks_obj) }, diff --git a/shared-bindings/sdcardio/SDCard.h b/shared-bindings/sdcardio/SDCard.h index ac27b47aa4d21..95998f5af5e90 100644 --- a/shared-bindings/sdcardio/SDCard.h +++ b/shared-bindings/sdcardio/SDCard.h @@ -13,7 +13,9 @@ extern const mp_obj_type_t sdcardio_SDCard_type; void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *cs, int baudrate); void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self); +bool common_hal_sdcardio_sdcard_deinited(sdcardio_sdcard_obj_t *self); void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); +void common_hal_sdcardio_sdcard_mark_deinit(sdcardio_sdcard_obj_t *self); int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self); int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index f3444241b3cca..3ffd4d002f534 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -13,6 +13,7 @@ #include "py/runtime.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/busio/I2C.h" +#include "shared-bindings/busio/SPI.h" #include "shared-bindings/displayio/Bitmap.h" #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/Palette.h" @@ -221,6 +222,7 @@ void reset_displays(void) { #endif memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t)); fourwire->bus = &fourwire->inline_bus; + // Check for other display buses that use the same spi bus and swap them too. for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) { if (display_buses[j].fourwire_bus.base.type == &fourwire_fourwire_type && @@ -228,6 +230,8 @@ void reset_displays(void) { display_buses[j].fourwire_bus.bus = &fourwire->inline_bus; } } + // Mark the old SPI object so it is considered deinit. + common_hal_busio_spi_mark_deinit(original_spi); } #endif #if CIRCUITPY_I2CDISPLAYBUS diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index bd3ea62d141e5..878fed7a13c9b 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -32,18 +32,41 @@ #define TOKEN_STOP_TRAN (0xFD) #define TOKEN_DATA (0xFE) +bool common_hal_sdcardio_sdcard_deinited(sdcardio_sdcard_obj_t *self) { + // Also check SPI bus was deinited out from under us. + if (!self->bus || common_hal_busio_spi_deinited(self->bus)) { + return true; + } + return false; +} + +void common_hal_sdcardio_sdcard_mark_deinit(sdcardio_sdcard_obj_t *self) { + self->bus = NULL; +} + static void common_hal_sdcardio_check_for_deinit(sdcardio_sdcard_obj_t *self) { - if (!self->bus) { + if (common_hal_sdcardio_sdcard_deinited(self)) { raise_deinited_error(); } } static bool lock_and_configure_bus(sdcardio_sdcard_obj_t *self) { + if (common_hal_sdcardio_sdcard_deinited(self)) { + return false; + } common_hal_sdcardio_check_for_deinit(self); if (!common_hal_busio_spi_try_lock(self->bus)) { return false; } + + // Make sure we can still use the SPI bus after grabbing the lock. + // The VM might be in the process of shutting down, and there could be a race. + if (!vm_is_running() && !self->persistent_mount) { + common_hal_busio_spi_unlock(self->bus); + return false; + } + common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8); common_hal_digitalio_digitalinout_set_value(&self->cs, false); return true; @@ -97,7 +120,7 @@ static int wait_for_ready(sdcardio_sdcard_obj_t *self) { } // Note: this is never called while "in cmd25" (in fact, it's only used by `exit_cmd25`) -static bool cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { +static int cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { uint8_t cmdbuf[2] = {cmd, 0xff}; assert(!self->in_cmd25); @@ -111,7 +134,7 @@ static bool cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { return 0; } } - return -EIO; + return -MP_EIO; } @@ -160,7 +183,7 @@ static int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf } if (!response_received) { - return -EIO; + return -MP_EIO; } if (response_buf) { @@ -294,13 +317,16 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { return NULL; } -mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate) { +mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate, bool persistent_mount) { self->bus = bus; + self->persistent_mount = persistent_mount; common_hal_digitalio_digitalinout_construct(&self->cs, cs); common_hal_digitalio_digitalinout_switch_to_output(&self->cs, true, DRIVE_MODE_PUSH_PULL); self->cdv = 512; self->sectors = 0; + + // During initialization, talk to the SPI card between 100 khZ and 400 kHz. After that, can use full speed. self->baudrate = 250000; lock_bus_or_throw(self); @@ -318,18 +344,19 @@ mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate) { - mp_rom_error_text_t result = sdcardio_sdcard_construct(self, bus, cs, baudrate); + // User mounted, so persistent_mount=false. + mp_rom_error_text_t result = sdcardio_sdcard_construct(self, bus, cs, baudrate, false); if (result != NULL) { mp_raise_OSError_msg(result); } } void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self) { - if (!self->bus) { + if (common_hal_sdcardio_sdcard_deinited(self)) { return; } common_hal_sdcardio_sdcard_sync(self); - self->bus = 0; + common_hal_sdcardio_sdcard_mark_deinit(self); common_hal_digitalio_digitalinout_deinit(&self->cs); } @@ -428,7 +455,7 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t DEBUG_PRINT("i=%02d cmd[0] = 0x%02x\n", i, cmd[0]); if ((cmd[0] & 0b00010001) == 0b00000001) { if ((cmd[0] & 0x1f) != 0x5) { - return -EIO; + return -MP_EIO; } else { break; } @@ -489,14 +516,10 @@ int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self) { } int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { - // deinit check is in lock_and_configure_bus() if (buf->len % 512 != 0) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 512); } - lock_and_configure_bus(self); - int r = sdcardio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), buf->buf, start_block, buf->len / 512); - extraclock_and_unlock_bus(self); - return r; + return sdcardio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), buf->buf, start_block, buf->len / 512); } bool sdcardio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *out_value) { @@ -504,11 +527,8 @@ bool sdcardio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *o *out_value = 0; switch (cmd) { case MP_BLOCKDEV_IOCTL_DEINIT: - common_hal_sdcardio_sdcard_sync(self); - break; // TODO properly case MP_BLOCKDEV_IOCTL_SYNC: - common_hal_sdcardio_sdcard_sync(self); - break; + return common_hal_sdcardio_sdcard_sync(self) == 0; case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: *out_value = common_hal_sdcardio_sdcard_get_blockcount(self); break; diff --git a/shared-module/sdcardio/SDCard.h b/shared-module/sdcardio/SDCard.h index f9cd64b812532..35a9ed1bf3c12 100644 --- a/shared-module/sdcardio/SDCard.h +++ b/shared-module/sdcardio/SDCard.h @@ -23,6 +23,9 @@ typedef struct { uint32_t sectors; uint32_t next_block; bool in_cmd25; + // Automounted SD cards are usually persistent across VM's. Note this as needed to allow access + // when the VM is not running. + bool persistent_mount; } sdcardio_sdcard_obj_t; -mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate); +mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate, bool persistent_mount); diff --git a/shared-module/sdcardio/__init__.c b/shared-module/sdcardio/__init__.c index 29c890c6870c1..4a7a4d500cc3f 100644 --- a/shared-module/sdcardio/__init__.c +++ b/shared-module/sdcardio/__init__.c @@ -22,7 +22,7 @@ static mp_vfs_mount_t _sdcard_vfs; fs_user_mount_t _sdcard_usermount; static bool _init_error = false; -static bool _mounted = false; +static bool _automounted = false; #ifdef DEFAULT_SD_MOSI static busio_spi_obj_t busio_spi_obj; @@ -45,7 +45,7 @@ void automount_sd_card(void) { if (common_hal_digitalio_digitalinout_get_value(&sd_card_detect_pin) != DEFAULT_SD_CARD_INSERTED) { // No card. _init_error = false; - if (_mounted) { + if (_automounted) { // Unmount the card. mp_vfs_mount_t *cur = MP_STATE_VM(vfs_mount_table); if (cur == &_sdcard_vfs) { @@ -63,11 +63,11 @@ void automount_sd_card(void) { #ifdef DEFAULT_SD_MOSI common_hal_busio_spi_deinit(&busio_spi_obj); #endif - _mounted = false; + _automounted = false; } return; - } else if (_init_error || _mounted) { - // We've already tried and failed to init the card. Don't try again. + } else if (_init_error || _automounted) { + // We've already tried and failed to init the card, or it's still mounted. Don't try again. return; } @@ -81,10 +81,10 @@ void automount_sd_card(void) { common_hal_busio_spi_never_reset(spi_obj); #endif sdcard.base.type = &sdcardio_SDCard_type; - mp_rom_error_text_t error = sdcardio_sdcard_construct(&sdcard, spi_obj, DEFAULT_SD_CS, 25000000); + mp_rom_error_text_t error = sdcardio_sdcard_construct(&sdcard, spi_obj, DEFAULT_SD_CS, 25000000, true); if (error != NULL) { // Failed to communicate with the card. - _mounted = false; + _automounted = false; _init_error = true; #ifdef DEFAULT_SD_MOSI common_hal_busio_spi_deinit(spi_obj); @@ -104,7 +104,7 @@ void automount_sd_card(void) { // mount the block device so the VFS methods can be used FRESULT res = f_mount(&vfs->fatfs); if (res != FR_OK) { - _mounted = false; + _automounted = false; _init_error = true; common_hal_sdcardio_sdcard_deinit(&sdcard); #ifdef DEFAULT_SD_MOSI @@ -122,6 +122,6 @@ void automount_sd_card(void) { sdcard_vfs->obj = MP_OBJ_FROM_PTR(&_sdcard_usermount); sdcard_vfs->next = MP_STATE_VM(vfs_mount_table); MP_STATE_VM(vfs_mount_table) = sdcard_vfs; - _mounted = true; + _automounted = true; #endif // DEFAULT_SD_CARD_DETECT } diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index febede876bbf5..adc182497617c 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -5,7 +5,6 @@ // SPDX-License-Identifier: MIT #include "tusb.h" -// // #include "supervisor/flash.h" // For updating fatfs's cache #include "extmod/vfs.h" @@ -14,6 +13,7 @@ #include "lib/oofatfs/ff.h" #include "py/gc.h" #include "py/mpstate.h" +#include "py/runtime.h" #include "shared-module/storage/__init__.h" #include "supervisor/filesystem.h" @@ -28,7 +28,7 @@ #define SAVES_COUNT 0 #endif -#if CIRCUITPY_SDCARDIO +#if CIRCUITPY_SDCARD_USB #include "shared-module/sdcardio/__init__.h" #define SDCARD_COUNT 1 @@ -137,7 +137,8 @@ static fs_user_mount_t *get_vfs(int lun) { if (lun == SAVES_LUN) { const char *path_under_mount; fs_user_mount_t *saves = filesystem_for_path("/saves", &path_under_mount); - if (saves != root && (saves->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0 && !gc_ptr_on_heap(saves)) { + if (saves != root && + (saves->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0 && !gc_ptr_on_heap(saves)) { return saves; } } @@ -146,8 +147,15 @@ static fs_user_mount_t *get_vfs(int lun) { if (lun == SDCARD_LUN) { const char *path_under_mount; fs_user_mount_t *sdcard = filesystem_for_path("/sd", &path_under_mount); - // If "/sd" is on the root filesystem, nothing has been mounted there. - if (sdcard != root && (sdcard->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0) { + // If sdcard ("/sd") is on the root filesystem, nothing has been mounted there, so don't + // return it as a separate filesystem. + // If the SD card was automounted at startup, then it persists across VMs and its fs_user_mount_t is + // not on the heap. + // If the SD card filesystem was mounted by the user using heap objects, + // it should not be used when the VM has stopped running. + if ((sdcard != root) && + ((sdcard->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0) && + (vm_is_running() || !gc_ptr_on_heap(sdcard))) { return sdcard; } else { // Clear any ejected state so that a re-insert causes it to reappear. @@ -359,7 +367,7 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { return false; } - #if CIRCUITPY_SDCARD_USB + #ifdef SDCARD_LUN if (lun == SDCARD_LUN) { automount_sd_card(); }