Fix crash when getting board.SPI outside the VM

If one of the default pins was already in use it would crash.

The internal API has been refined to allow us to get the value
without causing an init of the singleton.

Fixes #1753
This commit is contained in:
Scott Shawcroft 2019-04-05 19:06:37 -07:00
parent 8b9e93329d
commit 7686f93ef4
No known key found for this signature in database
GPG Key ID: FD0EDC4B6C53CA59
8 changed files with 49 additions and 18 deletions

View File

@ -72,7 +72,7 @@ void board_init(void) {
displayio_fourwire_obj_t* bus = &displays[0].fourwire_bus;
bus->base.type = &displayio_fourwire_type;
common_hal_displayio_fourwire_construct(bus,
board_spi(),
common_hal_board_create_spi(),
&pin_PA28, // Command or data
&pin_PA01, // Chip select
&pin_PA27); // Reset

View File

@ -49,6 +49,11 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct(
return DIGITALINOUT_OK;
}
void common_hal_digitalio_digitalinout_never_reset(
digitalio_digitalinout_obj_t *self) {
never_reset_pin_number(self->pin->number);
}
bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t* self) {
return self->pin == mp_const_none;
}

View File

@ -52,5 +52,6 @@ void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj
digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t* self);
void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull);
digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self);
void common_hal_digitalio_digitalinout_never_reset(digitalio_digitalinout_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H

View File

@ -190,7 +190,7 @@ void reset_displays(void) {
if (((uint32_t) fourwire->bus) < ((uint32_t) &displays) ||
((uint32_t) fourwire->bus) > ((uint32_t) &displays + CIRCUITPY_DISPLAY_LIMIT)) {
busio_spi_obj_t* original_spi = fourwire->bus;
if (original_spi == board_spi()) {
if (original_spi == common_hal_board_get_spi()) {
continue;
}
memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t));

View File

@ -71,23 +71,42 @@ MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c);
STATIC busio_spi_obj_t spi_obj;
STATIC mp_obj_t spi_singleton = NULL;
mp_obj_t board_spi(void) {
if (spi_singleton == NULL) {
busio_spi_obj_t *self = &spi_obj;
self->base.type = &busio_spi_type;
assert_pin_free(DEFAULT_SPI_BUS_SCK);
assert_pin_free(DEFAULT_SPI_BUS_MOSI);
assert_pin_free(DEFAULT_SPI_BUS_MISO);
const mcu_pin_obj_t* clock = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_SCK);
const mcu_pin_obj_t* mosi = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MOSI);
const mcu_pin_obj_t* miso = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MISO);
common_hal_busio_spi_construct(self, clock, mosi, miso);
spi_singleton = (mp_obj_t)self;
}
// TODO(tannewt): Move this to shared-bindings/board/__init__.c and corresponding shared-module.
mp_obj_t common_hal_board_get_spi(void) {
return spi_singleton;
}
#else
mp_obj_t common_hal_board_create_spi(void) {
if (spi_singleton != NULL) {
return spi_singleton;
}
busio_spi_obj_t *self = &spi_obj;
self->base.type = &busio_spi_type;
if (!common_hal_mcu_pin_is_free(DEFAULT_SPI_BUS_SCK) ||
!common_hal_mcu_pin_is_free(DEFAULT_SPI_BUS_MOSI) ||
!common_hal_mcu_pin_is_free(DEFAULT_SPI_BUS_MISO)) {
return NULL;
}
const mcu_pin_obj_t* clock = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_SCK);
const mcu_pin_obj_t* mosi = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MOSI);
const mcu_pin_obj_t* miso = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MISO);
common_hal_busio_spi_construct(self, clock, mosi, miso);
spi_singleton = (mp_obj_t)self;
return spi_singleton;
}
mp_obj_t board_spi(void) {
mp_obj_t singleton = common_hal_board_get_spi();
if (singleton != NULL) {
return singleton;
}
assert_pin_free(DEFAULT_SPI_BUS_SCK);
assert_pin_free(DEFAULT_SPI_BUS_MOSI);
assert_pin_free(DEFAULT_SPI_BUS_MISO);
return common_hal_board_create_spi();
}
#else
mp_obj_t common_hal_board_spi(void) {
mp_raise_NotImplementedError(translate("No default SPI bus"));
return NULL;
}

View File

@ -29,7 +29,8 @@
#include "py/obj.h"
mp_obj_t board_i2c(void);
mp_obj_t common_hal_board_get_spi(void);
mp_obj_t common_hal_board_create_spi(void);
MP_DECLARE_CONST_FUN_OBJ_0(board_i2c_obj);
mp_obj_t board_spi(void);

View File

@ -132,11 +132,15 @@ bool spi_flash_read_data(uint32_t address, uint8_t* data, uint32_t data_length)
}
void spi_flash_init(void) {
cs_pin.base.type = &digitalio_digitalinout_type;
common_hal_digitalio_digitalinout_construct(&cs_pin, SPI_FLASH_CS_PIN);
// Set CS high (disabled).
common_hal_digitalio_digitalinout_switch_to_output(&cs_pin, true, DRIVE_MODE_PUSH_PULL);
common_hal_digitalio_digitalinout_never_reset(&cs_pin);
spi.base.type = &busio_spi_type;
common_hal_busio_spi_construct(&spi, SPI_FLASH_SCK_PIN, SPI_FLASH_MOSI_PIN, SPI_FLASH_MISO_PIN);
common_hal_busio_spi_never_reset(&spi);
}

View File

@ -77,7 +77,8 @@ safe_mode_t wait_for_safe_mode_reset(void) {
return NO_SAFE_MODE;
}
void reset_into_safe_mode(safe_mode_t reason) {
// Inline this so it's easy to break on it from GDB.
void __attribute__((noinline,)) reset_into_safe_mode(safe_mode_t reason) {
if (current_safe_mode > BROWNOUT && reason > BROWNOUT) {
while (true) {
// This very bad because it means running in safe mode didn't save us. Only ignore brownout