diff --git a/radio/src/drivers/frftl.cpp b/radio/src/drivers/frftl.cpp index a47132820c0..02ef61ec689 100644 --- a/radio/src/drivers/frftl.cpp +++ b/radio/src/drivers/frftl.cpp @@ -63,6 +63,10 @@ #define SECTOR_SIZE 512 #define PAGE_SIZE 4096 +#define BLOCK_SIZE 32768 +#define BLOCK_MASK (BLOCK_SIZE - 1) +#define PAGES_PER_BLOCK (BLOCK_SIZE / PAGE_SIZE) +#define USE_BLOCK_ERASE_THRESHOLD 4 #define SECTORS_PER_PAGE (PAGE_SIZE / SECTOR_SIZE) #define TT_PAGE_MAGIC 0xEF87364A #define TT_RECORDS_PER_PAGE 1024 @@ -541,6 +545,42 @@ static uint16_t allocatePhysicalPage(FrFTL* ftl) return physicalPageNo; } +static bool quickErase(FrFTL* ftl, uint32_t addr) +{ + + const FrFTLOps* cb = ftl->callbacks; + if ((addr & BLOCK_MASK) == 0) { + // Block aligned + + uint16_t ppn = addr / PAGE_SIZE; + uint8_t count = 0; + bool hasUsed = false; + + // Check state of the whole jumbo page + for (uint8_t i = 0; i < PAGES_PER_BLOCK; i++) { + PhysicalPageState state = getPhysicalPageState(ftl, ppn + i); + if (state == UNKNOWN || state == ERASE_REQUIRED) { + count++; + } + if (state == USED) { + hasUsed = true; + break; // Cannot use block erase + } + } + + if (!hasUsed && count >= USE_BLOCK_ERASE_THRESHOLD) { + bool ret = cb->flashBlockErase(addr); + if (ret) { + for (uint8_t i = 0; i < PAGES_PER_BLOCK; i++) { + setPhysicalPageState(ftl, ppn + i, ERASED); + } + } + return ret; + } + } + return cb->flashErase(addr); +} + static bool programPage(FrFTL* ftl, PageBuffer* buffer, bool doErase) { const FrFTLOps* cb = ftl->callbacks; @@ -548,7 +588,7 @@ static bool programPage(FrFTL* ftl, PageBuffer* buffer, bool doErase) if (doErase && getPhysicalPageState(ftl, buffer->physicalPageNo) != ERASED) { // Do erase on the fly - if (!cb->flashErase(pageAddr)) { + if (!quickErase(ftl, pageAddr)) { return false; } } @@ -991,7 +1031,7 @@ void createFTL(FrFTL* ftl) const FrFTLOps* cb = ftl->callbacks; do { if (getPhysicalPageState(ftl, i) != ERASED) { - cb->flashErase(addr); + quickErase(ftl, addr); } cb->flashProgram(addr, (const uint8_t*)&tt, PAGE_SIZE); setPhysicalPageState(ftl, i, USED); @@ -1010,7 +1050,7 @@ void createFTL(FrFTL* ftl) } while(++i < ftl->ttPageCount); if (getPhysicalPageState(ftl, 0) != ERASED) { - cb->flashErase(0); + quickErase(ftl, 0); } cb->flashProgram(0, (const uint8_t*)&tt, PAGE_SIZE); diff --git a/radio/src/drivers/frftl.h b/radio/src/drivers/frftl.h index 28ad44f5b98..d5b867b08c6 100644 --- a/radio/src/drivers/frftl.h +++ b/radio/src/drivers/frftl.h @@ -48,6 +48,7 @@ typedef struct { bool (*flashRead)(uint32_t addr, uint8_t* buf, uint32_t len); bool (*flashProgram)(uint32_t addr, const uint8_t* buf, uint32_t len); bool (*flashErase)(uint32_t addr); + bool (*flashBlockErase)(uint32_t addr); bool (*isFlashErased)(uint32_t addr); } FrFTLOps; diff --git a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp index 49a73381d7f..603bed01104 100644 --- a/radio/src/targets/common/arm/stm32/bootloader/boot.cpp +++ b/radio/src/targets/common/arm/stm32/bootloader/boot.cpp @@ -62,7 +62,7 @@ #endif #if defined(SPI_FLASH) - #include "spi_flash.h" + #include "diskio_spi_flash.h" #define SEL_CLEAR_FLASH_STORAGE_MENU_LEN 2 #endif @@ -537,7 +537,9 @@ int bootloaderMain() lcdRefresh(); if(event != EVT_KEY_BREAK(KEY_ENTER)) continue; - flashSpiEraseAll(); + sdDone(); + spiFlashDiskEraseAll(); + sdInit(); vpos = 0; state = ST_START; #endif diff --git a/radio/src/targets/common/arm/stm32/diskio_spi.cpp b/radio/src/targets/common/arm/stm32/diskio_spi.cpp index eb479745743..c98d9ffab5d 100644 --- a/radio/src/targets/common/arm/stm32/diskio_spi.cpp +++ b/radio/src/targets/common/arm/stm32/diskio_spi.cpp @@ -45,6 +45,10 @@ static const stm32_spi_t _sd_spi_hw = { .DMA_Channel = SD_SPI_DMA_CHANNEL, .txDMA_Stream = SD_SPI_DMA_TX_STREAM, .rxDMA_Stream = SD_SPI_DMA_RX_STREAM, + .DMA_FIFOMode = LL_DMA_FIFOMODE_ENABLE, + .DMA_FIFOThreshold = LL_DMA_FIFOTHRESHOLD_1_2, + .DMA_MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD, + .DMA_MemBurst = LL_DMA_MBURST_INC4, }; static uint32_t _sdcard_sectors; diff --git a/radio/src/targets/common/arm/stm32/diskio_spi_flash.cpp b/radio/src/targets/common/arm/stm32/diskio_spi_flash.cpp index 3f8dc014b6f..91dc07cf54f 100644 --- a/radio/src/targets/common/arm/stm32/diskio_spi_flash.cpp +++ b/radio/src/targets/common/arm/stm32/diskio_spi_flash.cpp @@ -64,6 +64,12 @@ static bool flashErase(uint32_t addr) return true; } +static bool flashBlockErase(uint32_t addr) +{ + flashSpiBlockErase(addr); + return true; +} + static bool isFlashErased(uint32_t addr) { return flashSpiIsErased(addr); @@ -73,9 +79,10 @@ static const FrFTLOps _frftl_cb = { .flashRead = flashRead, .flashProgram = flashWrite, .flashErase = flashErase, + .flashBlockErase = flashBlockErase, .isFlashErased = isFlashErased, }; -#endif +#endif // USE_FLASH_FTL static DSTATUS spi_flash_initialize(BYTE lun) { @@ -188,6 +195,17 @@ static DRESULT spi_flash_ioctl(BYTE lun, BYTE ctrl, void *buff) return res; } +void spiFlashDiskEraseAll() +{ +#if defined(USE_FLASH_FTL) + if (frftlInitDone) { + ftlDeInit(&_frftl); + frftlInitDone = false; + } +#endif + flashSpiEraseAll(); +} + const diskio_driver_t spi_flash_diskio_driver = { .initialize = spi_flash_initialize, .status = spi_flash_status, diff --git a/radio/src/targets/common/arm/stm32/diskio_spi_flash.h b/radio/src/targets/common/arm/stm32/diskio_spi_flash.h index 9732d6da4fa..25379621b62 100644 --- a/radio/src/targets/common/arm/stm32/diskio_spi_flash.h +++ b/radio/src/targets/common/arm/stm32/diskio_spi_flash.h @@ -23,4 +23,6 @@ #include "hal/fatfs_diskio.h" +void spiFlashDiskEraseAll(); + extern const diskio_driver_t spi_flash_diskio_driver; diff --git a/radio/src/targets/common/arm/stm32/spi_flash.cpp b/radio/src/targets/common/arm/stm32/spi_flash.cpp index c9e25567837..c54d1b1a323 100644 --- a/radio/src/targets/common/arm/stm32/spi_flash.cpp +++ b/radio/src/targets/common/arm/stm32/spi_flash.cpp @@ -74,10 +74,14 @@ const stm32_spi_t _flash_spi = { .SPI_Pins = FLASH_SPI_SCK_GPIO_PIN | FLASH_SPI_MISO_GPIO_PIN | FLASH_SPI_MOSI_GPIO_PIN, .CS_GPIOx = FLASH_SPI_CS_GPIO, .CS_Pin = FLASH_SPI_CS_GPIO_PIN, - .DMA = nullptr, - .DMA_Channel = 0, - .txDMA_Stream = 0, - .rxDMA_Stream = 0, + .DMA = FLASH_SPI_DMA, + .DMA_Channel = FLASH_SPI_DMA_CHANNEL, + .txDMA_Stream = FLASH_SPI_DMA_TX_STREAM, + .rxDMA_Stream = FLASH_SPI_DMA_RX_STREAM, + .DMA_FIFOMode = LL_DMA_FIFOMODE_ENABLE, + .DMA_FIFOThreshold = LL_DMA_FIFOTHRESHOLD_1_2, + .DMA_MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD, + .DMA_MemBurst = LL_DMA_MBURST_INC4, }; static SpiFlashDescriptor _flashDescriptor; @@ -95,11 +99,21 @@ static inline uint8_t flash_read_byte() return flash_rw_byte(0xFF); } -static void flash_rw_bytes(const uint8_t* tx, uint8_t* rx, uint16_t count) +static inline void flash_rw_bytes(const uint8_t* tx, uint8_t* rx, uint16_t count) { stm32_spi_transfer_bytes(&_flash_spi, tx, rx, count); } +static inline void flash_dma_read_bytes(uint8_t* buffer, uint16_t count) +{ + stm32_spi_dma_receive_bytes(&_flash_spi, buffer, count); +} + +static inline void flash_dma_write_bytes(const uint8_t* buffer, uint16_t count) +{ + stm32_spi_dma_transmit_bytes(&_flash_spi, buffer, count); +} + static inline void flash_put_cmd_addr(uint8_t cmd, uint32_t addr) { addr |= cmd << 24; @@ -293,7 +307,7 @@ uint32_t flashSpiRead(uint32_t address, uint8_t* data, uint32_t size) } else { flash_put_cmd_addr(FLASH_CMD_READ, address); } - flash_rw_bytes(0, data, size); + flash_dma_read_bytes(data, size); flash_unselect(); return size; @@ -317,7 +331,7 @@ uint32_t flashSpiWrite(uint32_t address, const uint8_t* data, uint32_t size) } else { flash_put_cmd_addr(FLASH_CMD_WRITE, address); } - flash_rw_bytes(data, 0, size); + flash_dma_write_bytes(data, size); flash_unselect(); flash_wait_for_not_busy(); diff --git a/radio/src/targets/common/arm/stm32/stm32_spi.cpp b/radio/src/targets/common/arm/stm32/stm32_spi.cpp index 7b1a2a15f22..d691d06dd58 100644 --- a/radio/src/targets/common/arm/stm32/stm32_spi.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_spi.cpp @@ -151,8 +151,10 @@ static void _config_dma_streams(const stm32_spi_t* spi) dmaInit.PeriphOrM2MSrcAddress = (uint32_t)&spi->SPIx->DR; dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH; - dmaInit.FIFOMode = LL_DMA_FIFOMODE_ENABLE; - dmaInit.FIFOThreshold = LL_DMA_FIFOTHRESHOLD_FULL; + dmaInit.FIFOMode = spi->DMA_FIFOMode; + dmaInit.FIFOThreshold = spi->DMA_FIFOThreshold; + dmaInit.MemoryOrM2MDstDataSize = spi->DMA_MemoryOrM2MDstDataSize; + dmaInit.MemBurst = spi->DMA_MemBurst; dmaInit.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; LL_DMA_Init(spi->DMA, spi->rxDMA_Stream, &dmaInit); diff --git a/radio/src/targets/common/arm/stm32/stm32_spi.h b/radio/src/targets/common/arm/stm32/stm32_spi.h index 114e411b0a5..78fa0874702 100644 --- a/radio/src/targets/common/arm/stm32/stm32_spi.h +++ b/radio/src/targets/common/arm/stm32/stm32_spi.h @@ -36,6 +36,10 @@ struct stm32_spi_t { uint32_t DMA_Channel; uint32_t txDMA_Stream; uint32_t rxDMA_Stream; + uint32_t DMA_FIFOMode; + uint32_t DMA_FIFOThreshold; + uint32_t DMA_MemoryOrM2MDstDataSize; + uint32_t DMA_MemBurst; }; void stm32_spi_enable_clock(SPI_TypeDef *SPIx); diff --git a/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp b/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp index 5b2b9869977..390335dc7af 100644 --- a/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp +++ b/radio/src/targets/common/arm/stm32/usbd_storage_msd.cpp @@ -256,7 +256,7 @@ int8_t STORAGE_Read_FS (uint8_t lun, */ int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { - WATCHDOG_SUSPEND(100/*1s*/); + WATCHDOG_SUSPEND(500/*5s*/); #if defined(FWDRIVE) if (lun == STORAGE_EEPROM_LUN) { diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 8194e6b5336..a5b7e8c4883 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -649,6 +649,10 @@ #define FLASH_SPI_SCK_GPIO_PIN LL_GPIO_PIN_5 // PA.05 #define FLASH_SPI_MISO_GPIO_PIN LL_GPIO_PIN_6 // PA.06 #define FLASH_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_7 // PA.07 + #define FLASH_SPI_DMA DMA2 + #define FLASH_SPI_DMA_CHANNEL LL_DMA_CHANNEL_3 + #define FLASH_SPI_DMA_TX_STREAM LL_DMA_STREAM_3 + #define FLASH_SPI_DMA_RX_STREAM LL_DMA_STREAM_5 // SPI1_TX: DMA2 Stream 3 (SDIO) / Stream 5 (Ext. module timer) // #define FLASH_SPI_TX_DMA_CHANNEL DMA_Channel_3 // #define FLASH_SPI_TX_DMA_STREAM DMA2_Stream3 @@ -671,6 +675,10 @@ #define FLASH_SPI_SCK_GPIO_PIN LL_GPIO_PIN_1 // PI.01 #define FLASH_SPI_MISO_GPIO_PIN LL_GPIO_PIN_2 // PI.02 #define FLASH_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_3 // PI.03 + #define FLASH_SPI_DMA DMA1 + #define FLASH_SPI_DMA_CHANNEL LL_DMA_CHANNEL_0 + #define FLASH_SPI_DMA_TX_STREAM LL_DMA_STREAM_4 + #define FLASH_SPI_DMA_RX_STREAM LL_DMA_STREAM_3 // #define FLASH_SPI_TX_DMA_CHANNEL DMA_Channel_0 // #define FLASH_SPI_TX_DMA_STREAM DMA1_Stream4 // #define FLASH_SPI_TX_DMA_IRQn DMA1_Stream4_IRQn diff --git a/radio/src/targets/nv14/hal.h b/radio/src/targets/nv14/hal.h index 5d357caed98..3552205f716 100644 --- a/radio/src/targets/nv14/hal.h +++ b/radio/src/targets/nv14/hal.h @@ -320,6 +320,10 @@ #define FLASH_SPI_SCK_GPIO_PIN LL_GPIO_PIN_13 // PG.13 #define FLASH_SPI_MISO_GPIO_PIN LL_GPIO_PIN_12 // PG.12 #define FLASH_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_14 // PG.14 +#define FLASH_SPI_DMA DMA2 +#define FLASH_SPI_DMA_CHANNEL LL_DMA_CHANNEL_1 +#define FLASH_SPI_DMA_TX_STREAM LL_DMA_STREAM_5 +#define FLASH_SPI_DMA_RX_STREAM LL_DMA_STREAM_6 // SDRAM #define SDRAM_RCC_AHB1Periph (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH) diff --git a/radio/src/targets/pl18/hal.h b/radio/src/targets/pl18/hal.h index 5c297d40aa5..cd3ace7318b 100644 --- a/radio/src/targets/pl18/hal.h +++ b/radio/src/targets/pl18/hal.h @@ -465,14 +465,10 @@ #define FLASH_SPI_SCK_GPIO_PIN LL_GPIO_PIN_13 // PG.13 #define FLASH_SPI_MISO_GPIO_PIN LL_GPIO_PIN_12 // PG.12 #define FLASH_SPI_MOSI_GPIO_PIN LL_GPIO_PIN_14 // PG.14 -// #define FLASH_SPI_DMA DMA2 -// #define FLASH_SPI_DMA_CHANNEL LL_DMA_CHANNEL_1 -// #define FLASH_SPI_DMA_TX_STREAM LL_DMA_STREAM_5 -// #define FLASH_SPI_DMA_TX_IRQn DMA2_Stream5_IRQn -// #define FLASH_SPI_DMA_TX_IRQHandler DMA2_Stream5_IRQHandler -// #define FLASH_SPI_DMA_RX_STREAM LL_DMA_STREAM_6 -// #define FLASH_SPI_DMA_RX_IRQn DMA2_Stream6_IRQn -// #define FLASH_SPI_DMA_RX_IRQHandler DMA2_Stream6_IRQHandler +#define FLASH_SPI_DMA DMA2 +#define FLASH_SPI_DMA_CHANNEL LL_DMA_CHANNEL_1 +#define FLASH_SPI_DMA_TX_STREAM LL_DMA_STREAM_5 +#define FLASH_SPI_DMA_RX_STREAM LL_DMA_STREAM_6 #define STORAGE_USE_SPI_FLASH // SDRAM