Commit d6a2d001 authored by Damien George's avatar Damien George
Browse files

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).
parent 784e023a
......@@ -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))
......
......@@ -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
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment