Skip to content

[spi_flash] handle reentrance gracefully #4397

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 23, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions supervisor/shared/external_flash/spi_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ const external_flash_device *flash_device;
uint32_t spi_flash_baudrate;

// Enable the flash over SPI.
static void flash_enable(void) {
while (!common_hal_busio_spi_try_lock(&supervisor_flash_spi_bus)) {
static bool flash_enable(void) {
if (common_hal_busio_spi_try_lock(&supervisor_flash_spi_bus)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth retrying X amount of times even? I know adafruit_bus_device had a routine to catch background tasks and keep trying for the lock, I'm not familiar enough to say for sure this needs it just a thought.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it be that instead of the busy-wait in https://github.com/adafruit/Adafruit_CircuitPython_BusDevice/blob/master/adafruit_bus_device/spi_device.py#L73, it's better to throw an exception when the SPI is locked? Then the user would have control over how many times, if at all, to retry.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looping over common_hal_busio_spi_try_lock() in C will not succeed if it doesn't work the first time: If foreground Python code has locked the bus, it has to be able to proceed in order to unlock the bus. I don't think we ever un/lock the bus from an interrupt context.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jepler doesn't the same apply to adafruit_bus_device? Or may run_background_tasks() lock SPI in one tick, and unlock it in another?

common_hal_digitalio_digitalinout_set_value(&cs_pin, false);
return true;
}
common_hal_digitalio_digitalinout_set_value(&cs_pin, false);
return false;
}

// Disable the flash over SPI.
Expand All @@ -54,8 +56,10 @@ static void flash_disable(void) {
common_hal_busio_spi_unlock(&supervisor_flash_spi_bus);
}

static bool transfer(uint8_t *command, uint32_t command_length, uint8_t *data_in, uint8_t *data_out, uint32_t data_length) {
flash_enable();
static bool transfer(uint8_t* command, uint32_t command_length, uint8_t* data_in, uint8_t* data_out, uint32_t data_length) {
if (!flash_enable()) {
return false;
}
bool status = common_hal_busio_spi_write(&supervisor_flash_spi_bus, command, command_length);
if (status) {
if (data_in != NULL && data_out != NULL) {
Expand Down Expand Up @@ -103,7 +107,9 @@ bool spi_flash_write_data(uint32_t address, uint8_t *data, uint32_t data_length)
uint8_t request[4] = {CMD_PAGE_PROGRAM, 0x00, 0x00, 0x00};
// Write the SPI flash write address into the bytes following the command byte.
address_to_bytes(address, request + 1);
flash_enable();
if (!flash_enable()) {
return false;
}
common_hal_busio_spi_configure(&supervisor_flash_spi_bus, spi_flash_baudrate, 0, 0, 8);
bool status = common_hal_busio_spi_write(&supervisor_flash_spi_bus, request, 4);
if (status) {
Expand All @@ -120,9 +126,11 @@ bool spi_flash_read_data(uint32_t address, uint8_t *data, uint32_t data_length)
request[0] = CMD_FAST_READ_DATA;
command_length = 5;
}
// Write the SPI flash write address into the bytes following the command byte.
// Write the SPI flash read address into the bytes following the command byte.
address_to_bytes(address, request + 1);
flash_enable();
if (!flash_enable()) {
return false;
}
common_hal_busio_spi_configure(&supervisor_flash_spi_bus, spi_flash_baudrate, 0, 0, 8);
bool status = common_hal_busio_spi_write(&supervisor_flash_spi_bus, request, command_length);
if (status) {
Expand Down