From d6a2d0016793ad962a8f2b6da48f2a64de84b023 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Jan 2017 16:58:50 +1100 Subject: [PATCH] stmhal: Add ability to have filesystem stored on external SPI flash. To use this feature a port should define MICROPY_HW_SPIFLASH_SIZE_BITS along with x_CS, x_SCK, x_MOSI, x_MISO (x=MICROPY_HW_SPIFLASH). This will then use external SPI flash on those pins instead of the internal flash. The SPI is done using the software implementation. There is currently only support for standard SPI (ie not dual or quad mode). --- stmhal/Makefile | 5 +++ stmhal/storage.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/stmhal/Makefile b/stmhal/Makefile index 9a9c50f065..87236068ba 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -117,6 +117,10 @@ SRC_LIB = $(addprefix lib/,\ utils/pyexec.c \ ) +DRIVERS_SRC_C = $(addprefix drivers/,\ + memory/spiflash.c \ + ) + SRC_C = \ main.c \ system_stm32.c \ @@ -256,6 +260,7 @@ endif OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_O)) OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o)) diff --git a/stmhal/storage.c b/stmhal/storage.c index 14b504d716..60a7e9f480 100644 --- a/stmhal/storage.c +++ b/stmhal/storage.c @@ -38,6 +38,14 @@ #include "storage.h" #include "irq.h" +#if defined(MICROPY_HW_SPIFLASH_SIZE_BITS) +#define USE_INTERNAL (0) +#else +#define USE_INTERNAL (1) +#endif + +#if USE_INTERNAL + #if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) #define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k @@ -158,19 +166,50 @@ static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) { return (uint8_t*)flash_addr; } +#else + +#include "drivers/memory/spiflash.h" +#include "genhdr/pins.h" + +#define FLASH_PART1_START_BLOCK (0x100) +#define FLASH_PART1_NUM_BLOCKS (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) + +static bool flash_is_initialised = false; + +STATIC const mp_spiflash_t spiflash = { + .cs = &MICROPY_HW_SPIFLASH_CS, + .spi = { + .base = {&mp_machine_soft_spi_type}, + .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY, + .polarity = 0, + .phase = 0, + .sck = &MICROPY_HW_SPIFLASH_SCK, + .mosi = &MICROPY_HW_SPIFLASH_MOSI, + .miso = &MICROPY_HW_SPIFLASH_MISO, + }, +}; + +#endif + void storage_init(void) { if (!flash_is_initialised) { + #if USE_INTERNAL flash_flags = 0; flash_cache_sector_id = 0; flash_tick_counter_last_write = 0; + #else + mp_spiflash_init((mp_spiflash_t*)&spiflash); + #endif flash_is_initialised = true; } + #if USE_INTERNAL // Enable the flash IRQ, which is used to also call our storage IRQ handler // It needs to go at a higher priority than all those components that rely on // the flash storage (eg higher than USB MSC). HAL_NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH, IRQ_SUBPRI_FLASH); HAL_NVIC_EnableIRQ(FLASH_IRQn); + #endif } uint32_t storage_get_block_size(void) { @@ -182,6 +221,8 @@ uint32_t storage_get_block_count(void) { } void storage_irq_handler(void) { + #if USE_INTERNAL + if (!(flash_flags & FLASH_FLAG_DIRTY)) { return; } @@ -222,10 +263,14 @@ void storage_irq_handler(void) { // indicate a clean cache with LED off led_state(PYB_LED_R1, 0); } + + #endif } void storage_flush(void) { + #if USE_INTERNAL flash_cache_flush(); + #endif } static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) { @@ -264,6 +309,8 @@ static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_blo buf[15] = num_blocks >> 24; } +#if USE_INTERNAL + static uint32_t convert_block_to_flash_addr(uint32_t block) { if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) { // a block in partition 1 @@ -279,6 +326,8 @@ static uint32_t convert_block_to_flash_addr(uint32_t block) { return -1; } +#endif + bool storage_read_block(uint8_t *dest, uint32_t block) { //printf("RD %u\n", block); if (block == 0) { @@ -299,6 +348,8 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { return true; } else { + #if USE_INTERNAL + // non-MBR block, get data from flash memory, possibly via cache uint32_t flash_addr = convert_block_to_flash_addr(block); if (flash_addr == -1) { @@ -308,6 +359,27 @@ bool storage_read_block(uint8_t *dest, uint32_t block) { uint8_t *src = flash_cache_get_addr_for_read(flash_addr); memcpy(dest, src, FLASH_BLOCK_SIZE); return true; + + #else + + // non-MBR block, get data from SPI flash + + if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) { + // bad block number + return false; + } + + // we must disable USB irqs to prevent MSC contention with SPI flash + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + mp_spiflash_read((mp_spiflash_t*)&spiflash, + (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, dest); + + restore_irq_pri(basepri); + + return true; + + #endif } } @@ -318,6 +390,8 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { return true; } else { + #if USE_INTERNAL + // non-MBR block, copy to cache uint32_t flash_addr = convert_block_to_flash_addr(block); if (flash_addr == -1) { @@ -327,6 +401,27 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { uint8_t *dest = flash_cache_get_addr_for_write(flash_addr); memcpy(dest, src, FLASH_BLOCK_SIZE); return true; + + #else + + // non-MBR block, write to SPI flash + + if (block < FLASH_PART1_START_BLOCK || block >= FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) { + // bad block number + return false; + } + + // we must disable USB irqs to prevent MSC contention with SPI flash + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + int ret = mp_spiflash_write((mp_spiflash_t*)&spiflash, + (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE, FLASH_BLOCK_SIZE, src); + + restore_irq_pri(basepri); + + return ret == 0; + + #endif } }